﻿using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Security.Cryptography;
using Microsoft.Win32;

namespace SFP
{
    public partial class SFP_main : Form
    {
        string logging = "off"; //by default

        public SFP_main()
        {
            InitializeComponent();
        }

        public void startlogging()
        {
            // Create the trace listener.
            if (File.Exists("sfp-log.txt"))
            {
                Stream sfplog = File.Open("sfp-log.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                Trace.Listeners.Add(new TextWriterTraceListener(sfplog));
            }
            else
            {
                Stream sfplog = File.Create("sfp-log.txt");
                TextWriterTraceListener listener = new TextWriterTraceListener(sfplog);
                Trace.Listeners.Add(listener);
            }
        }

        private string getapid(string i)
        {
            switch (i)
            {
                case "10f5a20c21466e85": return "FTP Voyager 15.2.0.17";
                case "1110d9896dceddb3": return "imgSeek 0.8.5";
                case "12dc1ea8e34b5a6": return "Microsoft Paint 6.1";
                case "135df2a440abe9bb": return "SoulSeek 156c";
                case "13eb0e5d9a49eaef": return "Binjet 3.0.2";
                case "1434d6d62d64857d": return "BitLord 1.2.0-66";
                case "1461132e553e2e6c": return "Firefox 6.0";
                case "169b3be0bc43d592": return "FastPictureViewer Professional 1.6 (Build 211)";
                case "16ec093b8f51508f": return "Opera 8.54 build 7730 / 9.64 build 10487 / 11.50 build 1074";
                case "17d3eb086439f0d7": return "TrueCrypt 7.0a";
                case "186b5ccada1d986b": return "NewsGrabber 3.0.36";
                case "19ccee0274976da8": return "mIRC 4.72 / 5.61";
                case "1a60b1067913516a": return "Psi 0.14";
                case "1b29f0dc90366bb": return "AIM 5.9.3857";
                case "1b4dd67f29cb1962": return "Windows Explorer Pinned and Recent";
                case "1bc392b8e104a00e": return "Remote Desktop";
                case "1cf97c38a5881255": return "MediaPortal 1.1.3";
                case "1cffbe973a437c74": return "DSPlayer 0.889 Lite";
                case "1da3c90a72bf5527": return "Safari 4.0.5 (531.22.7) / 5.1 (7534.50)";
                case "1eb796d87c32eff9": return "Firefox 5.0";
                case "20ef367747c22564": return "Bullet Proof FTP 2010.75.0.75";
                case "223bf0f360c6fea5": return "I2P 0.8.8 (restartable)";
                case "226400522157fe8b": return "FileZilla Server 0.9.39 beta";
                case "22cefa022402327d": return "Meca Messenger 5.3.0.52";
                case "23646679aaccfae0": return "Adobe Acrobat 9.4.0";
                case "23f08dab0f6aaf30": return "SoMud 1.3.3";
                case "2417caa1f2a881d4": return "ICQ 7.6 (Build 5617)";
                case "2437d4d14b056114": return "EiskaltDC++ 2.2.3";
                case "2519133d6d830f7e": return "IMatch 3.6.0.113";
                case "2544ff74641b639d": return "WiseFTP 6.1.5";
                case "26717493b25aa6e1": return "Adobe Dreamweaver CS5 (32-bit)";
                case "271e609288e1210a": return "Microsoft Office Access 2010 x86";
                case "27da120d7e75cf1f": return "pbFTPClient 6.1";
                case "27ececd8d89b6767": return "AIM 6.2.14.2 / 6.5.3.12 / 6.9.17.2";
                case "28c8b86deab549a1": return "Internet Explorer 8 / 9";
                case "2a5a615382a84729": return "X-Chat 2 2.8.6-2";
                case "2aa756186e21b320": return "RealTimeQuery 3.2";
                case "2b164f512891ae37": return "NewsWolf NSListGen";
                case "2b53c4ddf69195fc": return "Zune x64";
                case "2d1658d5dc3cbe2d": return "MySpaceIM 1.0.823.0 Beta";
                case "2d61cccb4338dfc8": return "BitTorrent 5.0.0 / 6.0.0 / 7.2.1 (Build 25548)";
                case "2db8e25112ab4453": return "Deluge 1.3.3";
                case "2fa14c7753239e4c": return "Paint.NET 2.72 / 3.5.8.4081.24580";
                case "2ff9dc8fb7e11f39": return "I2P 0.8.8 (no window)";
                case "3094cdb43bf5e9c2": return "Microsoft Office OneNote 2010 x86";
                case "30d23723bdd5d908": return "Digsby (Build 30140) (JL support)";
                case "3168cc975b354a01": return "Slypheed 3.1.2 (Build 1120)";
                case "3198e37206f28dc7": return "CuteFTP 8.3 Professional (Build 8.3.4.0007)";
                case "337ed59af273c758": return "Sticky Notes";
                case "3461e4d1eb393c9c": return "WTW 0.8.18.2852 / 0.8.19.2940";
                case "3594aab44bca414b": return "Windows Photo Viewer";
                case "36801066f71b73c5": return "Binbot 2.0";
                case "36c36598b08891bf": return "Vovox 2.5.3.4250";
                case "36f6bc3efe1d99e0": return "Alt.Binz 0.25.0 (Build 27.09.2007)";
                case "37392221756de927": return "RealPlayer SP 12";
                case "386a2f6aa7967f36": return "EyeBrowse 2.7";
                case "3917dd550d7df9a8": return "Konvertor 4.06 (Build 10)";
                case "3a5148bf2288a434": return "Secure FTP 2.6.1 (Build 20101209.1254)";
                case "3be7b307dfccb58f": return "NiouzeFire 0.8.7.0";
                case "3c0022d9de573095": return "QuteCom 2.2";
                case "3c93a049a30e25e6": return "J. River Media Center 16.0.149";
                case "3cf13d83b0bd3867": return "RevConnect 0.674p (based on DC++)";
                case "3d877ec11607fe4": return "Thunderbird 6.0.2";
                case "3dc02b55e44d6697": return "7-Zip 3.13 / 4.20";
                case "3ed70ef3495535f7": return "Gravity 3.0.4";
                case "3edf100b207e2199": return "digiKam 1.7.0 (KDE 4.4.4)";
                case "3f2cd46691bbee90": return "GOIM 1.1.0";
                case "3f97341a65bac63a": return "Ozum 6.07 (Build 6070)";
                case "4278d3dc044fc88a": return "Gaim 1.5.0";
                case "431a5b43435cc60b": return "Python (.pyc)";
                case "43578521d78096c6": return "Windows Media Player Classic Home Cinema 1.3 (32-bit)";
                case "435a2f986b404eb7": return "SmartFTP 4.0.1214.0";
                case "43886ba3395acdcc": return "Easy Post 3.0";
                case "44a398496acc926d": return "Adobe Premiere Pro CS5 (64-bit)";
                case "44a50e6c87bc012": return "Classic FTP Plus 2.15";
                case "454ef7dca3bb16b2": return "Exodus 0.10.0.0";
                case "469e4a7982cea4d4": return "? (.job)";
                case "490c000889535727": return "WinMX 4.9.3.0";
                case "4975d6798a8bdf66": return "7-Zip 4.65 / 9.20";
                case "497b42680f564128": return "Zoner PhotoStudio 13 (Build 7)";
                case "49b5edbd92d8cd58": return "FTP Commander 8.02";
                case "4a49906d074a3ad3": return "Media Go 1.8 (Build 121)";
                case "4a7e4f6a181d3d08": return "broolzShare";
                case "4aa2a5710da3efe0": return "DCSharpHub 2.0.0";
                case "4acae695c73a28c7": return "VLC 0.3.0 / 0.4.6";
                case "4b632cf2ceceac35": return "Robo-FTP Server 3.2.5";
                case "4b6925efc53a3c08": return "BCWipe 5.02.2 Task Manager 3.02.3";
                case "4cdf7858c6673f4b": return "Bullet Proof FTP 1.26";
                case "4d72cfa1d0a67418": return "Newsgroup Image Collector";
                case "4d8bdacf5265a04f": return "The KMPlayer 2.9.4.1434";
                case "4dd48f858b1a6ba7": return "Free Download Manager 3.0 (Build 852)";
                case "4e0ac37db19cba15": return "Xfire 1.138 (Build 44507)";
                case "4f24a7b84a7de5a6": return "Palringo 2.6.3 (r45983)";
                case "4fceec8e021ac978": return "CoffeeCup Free FTP 3.5.0.0";
                case "500b8c1d5302fc9c": return "Python (.pyw)";
                case "50620fe75ee0093": return "VMWare Player 3.1.4";
                case "521a29e5d22c13b4": return "Skype 1.4.0.84 / 2.5.0.154 / 3.8.0.139 / 4.2.0.187 / Skype 5.3.0.120 / 5.5.0.115 / 5.5.32.117";
                case "54c803dfc87b52ba": return "Nettalk 6.7.12";
                case "558c5bd9f906860a": return "BearShare Lite 5.2.5.1";
                case "560d789a6a42ad5a": return "DC++ 0.261 / 0.698 / 0.782 (r2402.1)";
                case "59e86071b87ac1c3": return "CuteFTP 8.3 (Build 8.3.4.0007)";
                case "59f56184c796cfd4": return "ACDSee Photo Manager 10 (Build 219)";
                case "5b186fc4a0b40504": return "Dtella 1.2.5 (Purdue network only)";
                case "5c450709f7ae4396": return "Firefox 1.0 / 2.0 / 3.0";
                case "5d696d521de238c3": return "Chrome 9.0.597.84 / 12.0.742.100 / 13.0.785.215";
                case "5d7b4175afdcc260": return "Shareaza 2.0.0.0";
                case "5da8f997fd5f9428": return "Internet Explorer x64";
                case "5df4765359170e26": return "Firefox 4.0.1";
                case "5e01ecaf82f7d8e": return "Scour Exchange 0.0.0.228";
                case "5ea2a50c7979fbdc": return "TrustyFiles 3.1.0.22";
                case "6059df4b02360af": return "Kadu 0.10.0 / 0.6.5.5";
                case "6224453d9701a612": return "BinTube 3.7.1.0 (requires VLC 10.5!)";
                case "62bff50b969c2575": return ";Quintessential Media Player 5.0 (Build 121) - also usage stats (times used tracks played total time used)";
                case "62dba7fb39bb0adc": return "Yahoo Messenger 7.5.0.647 / 8.1.0.421 / 9.0.0.2162 / 10.0.0.1270";
                case "65009083bfa6a094": return "(app launched via XPMode)";
                case "65f7dd884b016ab2": return "LimeChat 2.39";
                case "6728dd69a3088f97": return "Windows Command Processor - cmd.exe (64-bit)";
                case "689319b6547cda85": return "emesene 2.11.7";
                case "6a316aa67a46820b": return "Core FTP LE 1.3c (Build 1437) / 2.2 (Build 1689)";
                case "6a8b377d0f5cb666": return "WinSCP 2.3.0 (Build 146)";
                case "6aa18a60024620ae": return "GCN 2.9.1";
                case "6b3a5ce7ad4af9e4": return "IceChat 9 RC2";
                case "6bb54d82fa42128d": return "WinSCP 4.3.4 (Build 1428)";
                case "6bc3383cb68a3e37": return "iTunes 7.6.0.29 / 8.0.0.35";
                case "6e9d40a4c63bb562": return "Real Player Alternative 1.25 (Media Player Classic 6.4.8.2 / 6.4.9.0)";
                case "6f647f9488d7a": return "AIM 7.5.11.9 (custom AppID + JL support)";
                case "6fee01bd55a634fe": return "Smuxi 0.8.0.0";
                case "70b52cf73249257": return "Sococo 1.5.0.2274";
                case "714b179e552596df": return "Bullet Proof FTP 2.4.0 (Build 31)";
                case "7192f2de78fd9e96": return "TIFNY 5.0.3";
                case "728008617bc3e34b": return "eM Client 3.0.10206.0";
                case "73c6a317412687c2": return "Google Talk 1.0.0.104";
                case "73ce3745a843c0a4": return "FrostWire 5.1.4";
                case "7494a606a9eef18e": return "Crystal Player 1.98";
                case "74d7f43c1561fc1e": return "Windows Media Player 12 (32-bit)";
                case "7526de4a8b5914d9": return "Forte Agent 6.00 (Build 32.1186)";
                case "7593af37134fd767": return "RealPlayer 6.0.6.99 / 7 / 8 / 10.5";
                case "76689ff502a1fd9e": return "Imagine Image and Animation Viewer 1.0.7";
                case "76f6f1bd18c19698": return "aMule 2.2.6";
                case "776beb1fcfc6dfa5": return "Thunderbird 1.0.6 (20050716) / 3.0.2";
                case "777483d3cdac1727": return "Gajim 0.14.4";
                case "780732558f827a42": return "AutoPix 5.3.3";
                case "784182360de0c5b6": return "Kazaa Lite 1.7.1";
                case "7904145af324576e": return "Total Commander 7.56a (Build 16.12.2010)";
                case "792699a1373f1386": return "Piolet 3.1.1";
                case "79370f660ab51725": return "UploadFTP 2.0.1.0";
                case "7937df3c65790919": return "FTP Explorer 10.5.19 (Build 001)";
                case "7a7c60efd66817a2": return "Spotnet 1.7.4";
                case "7b2b4f995b54387d": return "News Reactor 20100224.16";
                case "7cb0735d45243070": return "CDisplay 1.8.1.0";
                case "7e4dca80246863e3": return "Control Panel";
                case "7fd04185af357bd5": return "UltraLeeacher 1.7.0.2969 / 1.8 Beta (Build 3490)";
                case "8172865a9d5185cb": return "Binreader 1.0 (Beta 1)";
                case "817bb211c92fd254": return "GOM Player 2.0.12.3375 / 2.1.28.5039";
                case "8211531a7918b389": return "Newsbin Pro 6.00 (Build 1019) (JL support)";
                case "83b03b46dcd30a0e": return "iTunes 9.0.0.70 / 9.2.1.5 / 10.4.1.10";
                case "84f066768a22cc4f": return "Adobe Photoshop CS5 (64-bit)";
                case "8628e76fd9020e81": return "Fling File Transfer Plus 2.24";
                case "86781fe8437db23e": return "Messenger Pro 2.66.6.3353";
                case "86b804f7a28a3c17": return "Miranda IM 0.6.8 / 0.7.6 / 0.8.27 / 0.9.9 / 0.9.29 (ANSI + Unicode)";
                case "884fd37e05659f3a": return "VZOchat 6.3.5";
                case "8904a5fd2d98b546": return "IceChat 7.70 20101031";
                case "89b0d939f117f75c": return "Adobe Acrobat 9 Pro Extended (32-bit)";
                case "8a1c1c7c389a5320": return "Safari 3.2.3 (525.29)";
                case "8bd5c6433ca967e9": return "ACDSee Photo Manager 2009 (v11.0 Build 113)";
                case "8c816c711d66a6b5": return "MSN Messenger 6.2.0137 / 7.0.0820";
                case "8deb27dfa31c5c2a": return "CoffeeCup Free FTP 4.4 (Build 1904)";
                case "8f852307189803b8": return "Far Manager 2.0.1807";
                case "90e5e8b21d7e7924": return "Winamp 3.0d (Build 488)";
                case "918e0ecb43d17e23": return "Notepad (32-bit)";
                case "92f1d5db021cd876": return "NewsLeecher 4.0 / 5.0 Beta 6";
                case "93b18adf1d948fa3": return "qutIM 0.2";
                case "954ea5f70258b502": return "Windows Script Host - wscript.exe (32-bit)";
                case "9560577fd87cf573": return "LeechFTP 1.3 (Build 207)";
                case "96252daff039437a": return "Lphant 7.0.0.112351";
                case "977a5d147aa093f4": return "Lphant 3.51";
                case "9839aec31243a928": return "Microsoft Office Excel 2010 (32-bit)";
                case "989d7545c2b2e7b2": return "IMVU 465.8.0.0";
                case "98b0ef1c84088": return "fulDC 6.78";
                case "99c15cf3e6d52b61": return "mldonkey 3.1.0";
                case "9a3bdae86d5576ee": return "WinSCP 3.2.1 (Build 174) / 3.8.0 (Build 312)";
                case "9ad1ec169bf2da7f": return "FlylinkDC++ r405 (Build 7358)";
                case "9b9cdc69c1c24e2b": return "Notepad (64-bit)";
                case "9c7cc110ff56d1bd": return "Microsoft Office Powerpoint 2010 (32-bit)";
                case "9dacebaa9ac8ca4e": return "TLNews Newsreader 2.2.0 (Build 2430)";
                case "9e0b3f677a26bbc4": return "BitKinex 3.2.3";
                case "9f03ae476ad461fa": return "GroupsAloud 1.0";
                case "9f5c7755804b850a": return "Windows Script Host - wscript.exe (64-bit)";
                case "9fda41b86ddcf1db": return "VLC 0.5.3 / 0.8.6i / 0.9.7 / 1.1.11";
                case "a1d19afe5a80f80": return "FileZilla 2.2.32";
                case "a31ec95fdd5f350f": return "BitComet 0.49 / 0.59 / 0.69 / 0.79 / 0.89 / 0.99 / 1.07 / 1.28";
                case "a3e0d98f5653b539": return "Instantbird 1.0 (20110623121653) (JL support)";
                case "a4def57ee99d77e9": return "Nomad News 1.43";
                case "a581b8002a6eb671": return "WiseFTP 5.5.9";
                case "a5db18f617e28a51": return "ICQ 6.5 (Build 2024)";
                case "a746f9625f7695e8": return "HeXHub 5.07";
                case "a75b276f6e72cf2a": return "Kazaa Lite Tools K++ 2.7.0 or WinMX 3.53";
                case "a777ad264b54abab": return "JetVideo 8.0.2.200 Basic";
                case "a79a7ce3c45d781": return "CuteFTP 7.1 (Build 06.06.2005.1)";
                case "a7bd71699cd38d1c": return "Microsoft Office Word 2010 (32-bit)";
                case "a8c43ef36da523b1": return "Microsoft Office Word 2003 Pinned and Recent.";
                case "a8df13a46d66f6b5": return "Kommute (Calypso) 0.24";
                case "aa11f575087b3bdc": return "Unzbin 2.6.8";
                case "ac3a63b839ac9d3a": return "Vuze 4.6.0.4";
                case "ac8920ed05001800": return "DMDirc 0.6.5";
                case "accca100973ef8dc": return "Azureus 2.0.8.4";
                case "ace8715529916d31": return "40tude Dialog 2.0.15.1 (Beta 38)";
                case "adecfb853d77462a": return "Microsoft Office Word 2007 Pinned and Recent.";
                case "ae069d21df1c57df": return "mIRC 6.35 / 7.19";
                case "ae3f2acd395b622e": return "QuickTime Player 6.5.1 / 7.0.3 / 7.5.5 (Build 249.13)";
                case "aedd2de3901a77f4": return "Pidgin 2.0.0 / 2.10.0 / 2.7.3";
                case "b0236d03c0627ac4": return "ICQ 5.1 / ICQLite Build 1068";
                case "b0459de4674aab56": return "Windows Virtual PC - vmwindow.exe (32- and 64-bit)";
                case "b06a975b62567622": return "Windows Live Messenger 8.5.1235.0517 BETA";
                case "b17d3d0c9ca7e29": return ";Picasa 3.8.0 (Build 117.43 0)";
                case "b223c3ffbc0a7a42": return "Bersirc 2.2.14";
                case "b3016b8da2077262": return "eMule 0.50a";
                case "b3965c840bf28ef4": return "AIM 4.8.2616";
                case "b39c5f226977725d": return "ACDSee Pro 8.1.99";
                case "b3f13480c2785ae": return "Paint 6.1 (build 7601: SP1)";
                case "b48ce76eda60b97": return "Shareaza 8.0.0.112300";
                case "b50ee40805bd280f": return "QuickTime Alternative 1.9.5 (Media Player Classic 6.4.9.1)";
                case "b6267f3fcb700b60": return "WiseFTP 4.1.0";
                case "b74736c2bd8cc8a5": return "WinZip 15.5 (9468)";
                case "b7cb1d1c1991accf": return "FlashFXP 4.0.0 (Build 1548)";
                case "b868d9201b866d96": return "Microsoft Lync 4.0.7577.0";
                case "b8c13a5dd8c455a2": return "Titan FTP Server 8.40 (Build 1338)";
                case "b8c29862d9f95832": return "Microsoft Office InfoPath 2010 x86";
                case "b91050d8b077a4e8": return "Windows Media Center x64";
                case "ba132e702c0147ef": return "KCeasy 0.19-rc1";
                case "ba3a45f7fd2583e1": return "Blubster 3.1.1";
                case "baea31eacd87186b": return "BinaryBoy 1.97 (Build 55)";
                case "bc0c37e84e063727": return "Windows Command Processor - cmd.exe (32-bit)";
                case "bcc705f705d8132b": return "Instan-t 5.2 (Build 2824)";
                case "bcd7ba75303acbcf": return "BitLord 1.1";
                case "bd249197a6faeff2": return "Windows Live Messenger 2011";
                case "be4875bb3e0c158f": return "CrossFTP 1.75a";
                case "be71009ff8bb02a2": return "Microsoft Office Outlook x86";
                case "bf483b423ebbd327": return "Binary Vortex 5.0";
                case "bf9ae1f46bd9c491": return "Nimbuzz 2.0.0 (rev 6266)";
                case "bfc1d76f16fa778f": return "Ares (Galaxy) 1.8.4 / 1.9.8 / 2.1.0 / 2.1.7.3041";
                case "bfe841f4d35c92b1": return "QuadSucker/News 5.0";
                case "c01d68e40226892b": return "ClicksAndWhistles 2.7.146";
                case "c02baf50d02056fc": return "FotoVac 1.0";
                case "c04f69101c131440": return "CuteFTP 5.0 (Build 50.6.10.2)";
                case "c2d349a0e756411b": return "Adobe Reader 8.1.2";
                case "c312e260e424ae76": return "Mail.Ru Agent 5.8 (JL support)";
                case "c5236fd5824c9545": return "PLAYXPERT 1.0.140.2822";
                case "c54b96f328bdc28d": return "WiseFTP 7.3.0";
                case "c5c24a503b1727df": return "XnView 1.98.2 Small / 1.98.2 Standard";
                case "c5ef839d8d1c76f4": return "LimeWire 5.2.13";
                case "c634153e7f5fce9c": return "IrfanView 3.10 / 4.30";
                case "c6f7b5bf1b9675e4": return "BitWise IM 1.7.3a";
                case "c71ef2c372d322d7": return "PGP Desktop 10";
                case "c765823d986857ba": return "Adobe Illustrator CS5 (32-bit)";
                case "c7a4093872176c74": return "Paint Shop Pro Pinned and Recent.";
                case "c845f3a6022d647c": return "Another File 2.03 (Build 2/7/2004)";
                case "c8aa3eaee3d4343d": return "Trillian 0.74 / 3.1 / 4.2.0.25 / 5.0.0.35 (JL support)";
                case "c8e4c10e5460b00c": return "iMesh 6.5.0.16898";
                case "c91d08dcfc39a506": return "SM Player 0.6.9 r3447";
                case "c9374251edb4c1a8": return "BitTornado T-0.3.17";
                case "c98ab5ccf25dda79": return "NewsShark 2.0";
                case "c9950c443027c765": return "WinZip 9.0 SR-1 (6224) / 10.0 (6667)";
                case "c99ddde925d26df3": return "Robo-FTP 3.7.9 CronMaker";
                case "ca1eb46544793057": return "RetroShare 0.5.2a (Build 4550)";
                case "ca942805559495e9": return "aMSN 0.98.4";
                case "cb1d97aca3fb7e6b": return "Newz Crawler 1.9.0 (Build 4100)";
                case "cb5250eaef7e3213": return "ApexDC++ 1.4.3.957";
                case "cb984e3bc7faf234": return "NewsRover 17.0 (Rev.0)";
                case "cbbe886eca4bfc2d": return "ExoSee 1.0.0";
                case "cbeb786f0132005d": return "VLC 0.7.2";
                case "cc4b36fbfb69a757": return "gtk-gnutella 0.97";
                case "cc76755e0f925ce6": return "AllPicturez 1.2";
                case "cca6383a507bac64": return "Gadu-Gadu 10.5.2.13164";
                case "ccb36ff8a8c03b4b": return "Azureus 2.5.0.4 / Vuze 3.0.5.0";
                case "cd2acd4089508507": return "AbsoluteTelnet 9.18 Lite";
                case "cd40ead0b1eb15ab": return "NNTPGrab 0.6.2";
                case "cd8cafb0fb6afdab": return "uTorrent 1.7.7 (Build 8179) / 1.8.5 / 2.0 / 2.21 (Build 25113) / 3.0 (Build 25583)";
                case "cdf30b95c55fd785": return "Microsoft Office Excel 2007";
                case "cf6379a9a987366e": return "Digibin 1.31";
                case "cfab0ec14b6f953": return "Express NewsPictures 2.41 (Build 08.05.07.0)";
                case "cfb56c56fa0f0a54": return "Mozilla 0.9.9";
                case "d0261ed6e16b200b": return "News File Grabber 4.6.0.4";
                case "d1fc019238236806": return "Newsgroup Commander Pro 9.05";
                case "d22ad6d9d20e6857": return "ALLPlayer 4.7";
                case "d28ee773b2cea9b2": return "3D-FTP 9.0 build 7";
                case "d33ecf70f0b74a77": return ";Picasa 2.2.0 (Build 28.08 0)";
                case "d3530c5294441522": return "HydraIRC 0.3.165";
                case "d3c5cf21e86b28af": return "SeaMonkey 2.3.3";
                case "d41746b133d17456": return "Tkabber 0.11.1";
                case "d460280b17628695": return "Java Binary";
                case "d53b52fb65bde78c": return "Android Newsgroup Downloader 6.2";
                case "d5c02fc7afbb3fd4": return "NNTPGrab 0.6.2 Server";
                case "d5c3931caad5f793": return "Adobe Soundbooth CS5 (32-bit)";
                case "d64d36b238c843a3": return "Microsoft Office InfoPath 2010 x86";
                case "d7528034b5bd6f28": return "Windows Live Mail Pinned and Recent.";
                case "d7666c416cba240c": return "NewsMan Pro 3.0.5.2";
                case "d7d647c92cd5d1e6": return "uTalk 2.6.4 r47692";
                case "d7db75db9cdd7c5d": return "Xnews 5.04.25";
                case "d8081f151f4bd8a5": return "CuteFTP 8.3 Lite (Build 8.3.4.0007)";
                case "d838aac097abece7": return "ACDSee Photo Manager 12 (Build 344)";
                case "da7e8de5b8273a0f": return "Yahoo Messenger 5.0.0.1226 / 6.0.0.1922";
                case "dba909a61476ccec": return "NewsWolf 1.41";
                case "dc64de6c91c18300": return "Brosix Communicator 3.1.3 (Build 110719 nid 1)";
                case "dd658a07478b46c2": return "PIRCH98 1.0.1.1190";
                case "de76415e0060ce13": return "Noworyta News Reader 2.9";
                case "dee18f19c7e3a2ec": return "PopNote 5.21";
                case "e0246018261a9ccc": return "qutIM 0.2.80.0";
                case "e0532b20aa26a0c9": return "QQ International 1.1 (2042)";
                case "e0f7a40340179171": return "imule 1.4.5 (rev. 749)";
                case "e107946bb682ce47": return "FileZilla 3.5.1";
                case "e1d47cb031dafb9f": return "BearShare 6.0.0.22717 / 8.1.0.70928 / 10.0.0.112380";
                case "e2a593822e01aed3": return "Adobe Flash CS5 (32-bit)";
                case "e30bbea3e1642660": return "Neebly 1.0.4";
                case "e31a6a8a7506f733": return "Image AXS Pro 4.1";
                case "e36bfc8972e5ab1d": return "XPS Viewer";
                case "e40cb5a291ad1a5b": return "Songbird 1.9.3 (Build 1959)";
                case "e42a8e0f4d9b8dcf": return "Sysax FTP Automation 5.15";
                case "e6ea77a1d4553872": return "Gnucleus 1.8.6.0";
                case "e6ee34ac9913c0a9": return "VLC 0.6.2";
                case "e6ef42224b845020": return "ALFTP 5.20.0.4";
                case "e70d383b15687e37": return "Notepad++ 5.6.8 (32-bit)";
                case "e73d9f534ed5618a": return "BitSpirit 1.2.0.228 / 2.0 / 2.6.3.168 / 2.7.2.239 / 2.8.0.072 / 3.1.0.077 / 3.6.0.550";
                case "e76a4ef13fbf2bb1": return "Manolito 3.1.1";
                case "e93dbdcede8623f2": return "Pandion 2.6.106";
                case "e9a39dfba105ea23": return "FastStone Image Viewer 4.6";
                case "ea83017cdd24374d": return "IrfanView Thumbnails";
                case "eab25958dbddbaa4": return "Binary News Reaper 2 (Beta 0.14.7.448)";
                case "eb3300e672136bc7": return "Stream Reactor 1.0 Beta 9 (uses VLC!)";
                case "eb7e629258d326a1": return "WindowWasher 6.6.1.18";
                case "ebd8c95d87f25154": return "Carrier 2.5.5";
                case "ecd21b58c2f65a2f": return "StealthNet 0.8.7.9";
                case "ed49e1e6ccdba2f5": return "GNUnet 0.8.1a";
                case "ed7a5cc3cca8d52a": return "CCleaner 1.32.345 / 1.41.544 / 2.36.1233 / 3.10.1525";
                case "edc786643819316c": return "HoneyView3 #5834";
                case "ee462c3b81abb6f6": return "Adobe Reader X 10.1.0";
                case "ef606b196796ebb": return "HP MediaSmart Photo";
                case "efb08d4e11e21ece": return "Paltalk Messenger 10.0 (Build 409)";
                case "f001ea668c0aa916": return "Cabos 0.8.2";
                case "f0468ce1ae57883d": return "Adobe Reader 7.1.0";
                case "f09b920bfb781142": return "Camfrog 4.0.47 / 5.5.0 / 6.1 (build 146) (JL support)";
                case "f1a4c04eebef2906": return "[i2p] Robert 0.0.29 Preferences";
                case "f214ca2dd40c59c1": return "FrostWire 4.20.9";
                case "f2cb1c38ab948f58": return "X-Chat 1.8.10 / 2.6.9 / 2.8.9";
                case "f5ac5390b9115fdb": return "Microsoft Office PowerPoint 2007";
                case "f61b65550a84027e": return "iMesh 11.0.0.112351";
                case "f64de962764b9b0f": return "FTPRush 1.1.3 / 2.15";
                case "f674c3a77cfe39d0": return "Winamp 2.95 / 5.1 / 5.621";
                case "f82607a219af2999": return "Cyberduck 4.1.2 (Build 8999)";
                case "f91fd0c57c4fe449": return "ExpanDrive 2.1.0";
                case "f920768fe275f7f4": return "Grabit 1.5.3 Beta (Build 909) / 1.6.2 (Build 940) / 1.7.2 Beta 4 (Build 997)";
                case "f92e607f9de02413": return "RealPlayer 14.0.6.666";
                case "fa496fe13dd62edf": return "KVIrc 3.4.2.1 / 4.0.4";
                case "fa7144034d7d083d": return "Directory Opus 10.0.2.0.4269 (JL tasks supported)";
                case "fb1f39d1f230480a": return "Bopup Messenger 5.6.2.9178 (all languages: en;du;fr;ger;rus;es)";
                case "fb230a9fe81e71a8": return "Yahoo Messenger 11.0.0.2014-us";
                case "fb7ca8059b8f2123": return "ooVoo 3.0.7.21";
                case "fc999f29bc5c3560": return "Robo-FTP 3.7.9";
                case "fe5e840511621941": return "JetAudio 5.1.9.3018 Basic / 6.2.5.8220 Basic / 7.0.0 Basic / 8.0.16.2000 Basic";
                case "ff224628f0e8103c": return "Morpheus 3.0.3.6";

                default: return "App ID Unknown";
            }
        }

        private void savecsv_format(DataGridView x)
        {
            SaveFileDialog s = new SaveFileDialog();
            s.Filter = "CSV Files (*.csv)|*.csv";
            if (s.ShowDialog() == DialogResult.OK)
            {
                string buffer_csv_return = "\r\n";
                // Create the output CSV file
                TextWriter T = new StreamWriter(s.FileName);

                DataTable csvoutput = x.DataSource as DataTable;
                // print column names first
                foreach (DataColumn column in csvoutput.Columns)
                {
                    string buffer_csv = string.Concat(column.ColumnName, ","); T.Write(buffer_csv);
                }
                T.Write(buffer_csv_return);

                // now print the actual data
                foreach (DataRow row in csvoutput.Rows)
                {
                    foreach (DataColumn column in csvoutput.Columns)
                    {
                        string buffer_csv = string.Concat(row[column], ","); T.Write(buffer_csv);
                    }
                    T.Write(buffer_csv_return);
                }
                T.Close();
                MessageBox.Show(string.Concat(Path.GetFileName(s.FileName), " saved sucessfully"));
            }

        }

        public string GetMD5HashFromStream(Stream file)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(file);
            return bytestostring(retVal, null);
        }

        public string GetMD5HashFromFile(String path)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            byte[] retVal = md5.ComputeHash(fileStream);
            return bytestostring(retVal, null);
        }

        public string bytestostring(byte[] toconvert, string type)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < toconvert.Length; i++)
            {
                sb.Append(toconvert[i].ToString("X2"));
                if (type == "mac" && i != (toconvert.Length - 1))
                {
                    sb.Append(":");
                }
            }
            return sb.ToString();
        }

        public string bytestostring_littleendian(byte[] toconvert)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = toconvert.Length - 1; i >= 0; i--)
            {
                sb.Append(toconvert[i].ToString("X2"));
            }
            return sb.ToString();
        }

        private void parselnk_setuptable(DataTable x, Panel panel, string type)
        {
            if (type == "lnk only")
            {
                tabControl_main.SelectedTab = tabControl_main.TabPages[0];
                // Make the .lnk panel visible.
                panel.Visible = true;
                dataGridView_lnk.Visible = false;
                statuslabel_lnk_filesparsed.Text = "";
                statuslabel_lnk_timetaken.Text = "";
            }
            else if (type == "embedded lnk")
            {
                // embedded lnk within a jump list
            }

            // Create the columns.
            x.Columns.Add("LNK File Name", typeof(string));
            x.Columns.Add("Linked Path", typeof(string));
            x.Columns.Add("LNK File Creation Time (Local)", typeof(DateTime));
            x.Columns.Add("LNK File Access Time (Local)", typeof(DateTime));
            x.Columns.Add("LNK File Written Time (Local)", typeof(DateTime));
            x.Columns.Add("Embedded Creation Time (Local)", typeof(DateTime));
            x.Columns.Add("Embedded Access Time (Local)", typeof(DateTime));
            x.Columns.Add("Embedded Written Time (Local)", typeof(DateTime));
            x.Columns.Add("File Size (Bytes)", typeof(uint));

            // Columns for the LinkInfo section.
            x.Columns.Add("Server Share Path", typeof(string));
            x.Columns.Add("NetBIOS Name", typeof(string));
            x.Columns.Add("Target Drive Type", typeof(string));
            x.Columns.Add("Volume Serial Number", typeof(string));
            x.Columns.Add("Volume Label", typeof(string));

            // Columns for the StringData section.
            x.Columns.Add("Description", typeof(string));
            x.Columns.Add("Relative Path", typeof(string));
            x.Columns.Add("Working Directory", typeof(string));
            x.Columns.Add("Command Line Args", typeof(string));
            x.Columns.Add("Current VolumeID", typeof(string));
            x.Columns.Add("Current ObjectID", typeof(string));
            x.Columns.Add("Current Mac Addr", typeof(string));
            x.Columns.Add("Birth VolumeID", typeof(string));
            x.Columns.Add("Birth ObjectID", typeof(string));
            x.Columns.Add("Birth Mac Addr", typeof(string));
            x.Columns.Add("MD5 Hash", typeof(string));
        }

        private int parselnk_dowork(string[] selected_folder, DataTable datatable)
        {
            int filecount = 0;
            foreach (string file in selected_folder)
            {
                if (Path.GetExtension(file) == ".lnk")
                {
                    filecount++;
                    statuslabel_lnk_filebeingparsed.Text = String.Concat("Currently parsing: ", Path.GetFileName(file));
                    parselnkstream(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read), file, datatable, 1, null);
                }
            }
            return filecount;
        }

        private int parsei30_dowork(string[] selected_folder, DataTable datatable)
        {
            int filecount = 0;
            foreach (string file in selected_folder)
            {
                filecount++;
                statuslabel_i30_filebeingparsed.Text = String.Concat("Currently parsing: ", Path.GetFileName(file));
                parsei30stream(File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read), file, datatable);
            }
            return filecount;
        }

        private void parselnk_finalisetable(DataTable datatable, DataGridView gridview, Panel panel)
        {
            // Set the gridview datasource.
            gridview.DataSource = datatable;

            // Sets the formatting of the grid.
            gridview.Columns["LNK File Creation Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["LNK File Access Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["LNK File Written Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["LNK File Creation Time (Local)"].Width = 111;
            gridview.Columns["LNK File Access Time (Local)"].Width = 111;
            gridview.Columns["LNK File Written Time (Local)"].Width = 111;
            gridview.Columns["Embedded Creation Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["Embedded Access Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["Embedded Written Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["Embedded Creation Time (Local)"].Width = 111;
            gridview.Columns["Embedded Access Time (Local)"].Width = 111;
            gridview.Columns["Embedded Written Time (Local)"].Width = 111;

            gridview.Refresh();
            dataGridView_lnk.Visible = true;
        }

        private void parsei30_finalisetable(DataTable datatable, DataGridView gridview, Panel panel)
        {
            // Set the gridview datasource.
            gridview.DataSource = datatable;

            // Sets the formatting of the grid.

            gridview.Refresh();
            dataGridView_i30.Visible = true;
        }

        private void parselnkstream(Stream x, string i, DataTable gv, int type, string dir_name)
        {
            Trace.Write(string.Concat(x.Length.ToString(), " Stream length\n"));
            // type = 1 for normal lnk stream.
            // type = 2 for lnk stream within jump-list.

            // Define our global variables.
            int lnkfilefalse_counter = 0, lnkfiletrue_counter = 0, header, temp;
            uint filesize = 0;
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[2];
            byte[] temp4 = new byte[4];
            byte[] temp8 = new byte[8];
            byte[] temp6 = new byte[6];
            byte[] temp16 = new byte[16];

            // for the embedded date and time
            DateTime? CreationTime = null;
            DateTime? AccessTime = null;
            DateTime? WriteTime = null;

            // for the LNK file date and time we need to set the variables and extract the information
            DateTime? CreationTime_lnkfile = File.GetCreationTime(i);
            DateTime? AccessTime_lnkfile = File.GetLastAccessTime(i);
            DateTime? WriteTime_lnkfile = File.GetLastWriteTime(i);
            

            // set vars
            int LinkInfoSize = 0;
            int LocalBasePathOffset, VolumeIDOffset, VolumeIDstructure_start, VolumeIDSize, CommonNetworkRelativeLinkOffset, CommonNetworkRelativeLinkSize;
            int NetNameOffset, DeviceNameOffset, VolumeLabelOffset, StringData_start, CommonPathSuffixOffset, Sig_extra;
            string VolumeSerialNumber = "", LocalBasePath = "", DriveType1 = "";
            string LinkInfoFlags = "", CommonNetworkRelativeLinkFlags = "", NetName = "";
            string DeviceName = "", NetworkProviderType = "", LinkedPath = "", VolumeLabel = "", IconLocation = "";
            string birthmacaddr = "", newmacaddr = "";

            // set StringData vars
            string NameString = "", RelativePath = "", WorkingDir = "", CommandLineArgs = "", NetBIOS = "";
            string VolumeID_current = "", ObjectID_current = "";
            string VolumeID_birth = "", ObjectID_birth = "";

            // Get MD5 hash.
            string md5hash = GetMD5HashFromStream(x);

            using (BinaryReader R = new BinaryReader(x))
                try
                {
                    // lets go from the start
                    R.BaseStream.Position = 0;

                    // read the header of a file, should be '76' in value
                    R.Read(temp4, 0, 4);
                    header = BitConverter.ToInt32(temp4, 0); //convert to a 32 bit value

                    // read lnk flags
                    R.BaseStream.Position = 20;
                    R.Read(temp4, 0, 1);
                    temp = BitConverter.ToInt32(temp4, 0); // convert bytes to number
                    string lnkflags = Convert.ToString(temp, 2); // convert number to binary
                    char[] charArray = lnkflags.ToCharArray();
                    Array.Reverse(charArray); // reverse the string
                    lnkflags = new string(charArray);
                    Trace.Write(string.Concat(R.BaseStream.Position.ToString(), " ", lnkflags, "LNKflags read\n"));

                    if (header == 76 && temp > 0) // check to see if this file is a valid lnk file
                    {
                        Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Valid LNK file\n"));
                        lnkfiletrue_counter++; // increment the good lnk file counter

                        // read all times in UTC
                        string timezone = "utc";
                        CreationTime = ReadTargetLnkTime(28, R, temp8, timezone, "no", 0);
                        AccessTime = ReadTargetLnkTime(36, R, temp8, timezone, "no", 0);
                        WriteTime = ReadTargetLnkTime(44, R, temp8, timezone, "no", 0);

                        // read target file size
                        R.BaseStream.Position = 52;
                        R.Read(temp4, 0, 4);
                        filesize = BitConverter.ToUInt32(temp4, 0);

                        // read HasLinkTargetIDList flag, if set (1) then continue
                        int IDListSize = 0;
                        if (lnkflags[0] == '1')
                        {
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Has LinkTargetIDList flag\n"));
                            R.BaseStream.Position = 76;
                            R.Read(temp4, 0, 2);
                            IDListSize = BitConverter.ToInt16(temp4, 0);
                        }
                        else if (lnkflags[0] == '0')
                        {
                            IDListSize = -2; // we need -2 here to correct the inkinfostructure_start offset
                        } 

                        // read HasLinkInfo flag, if set (1) then continue
                        if (lnkflags[1] == '1')
                        {
                            int lnkinfostructure_start = 78 + IDListSize; // save the start of the LNKINFO structure
                            // read LinkInfoSize
                            R.BaseStream.Position = lnkinfostructure_start;
                            R.Read(temp4, 0, 4);
                            LinkInfoSize = BitConverter.ToInt32(temp4, 0);
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "LNKINFO position start\n"));

                            // read LinkInfoFlags
                            R.BaseStream.Position = lnkinfostructure_start + 8;
                            R.Read(temp4, 0, 1);
                            temp = BitConverter.ToInt32(temp4, 0); // convert bytes to number
                            LinkInfoFlags = Convert.ToString(temp, 2); // convert number to binary
                            // reverse the string
                            char[] charArray1 = LinkInfoFlags.ToCharArray();
                            Array.Reverse(charArray1);
                            LinkInfoFlags = new string(charArray1);
                            lnkflags = lnkflags + " " + LinkInfoFlags;
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "LinkInfoFlags read\n"));

                            // READ OFFSETS
                            // read Volume ID Offset
                            R.BaseStream.Position = lnkinfostructure_start + 12;
                            R.Read(temp4, 0, 4);
                            VolumeIDOffset = BitConverter.ToInt32(temp4, 0);

                            // read LocalBasePathOffset
                            R.BaseStream.Position = lnkinfostructure_start + 16;
                            R.Read(temp4, 0, 4);
                            LocalBasePathOffset = BitConverter.ToInt32(temp4, 0);

                            // read common network relative link offset
                            R.BaseStream.Position = lnkinfostructure_start + 20;
                            R.Read(temp4, 0, 4);
                            CommonNetworkRelativeLinkOffset = BitConverter.ToInt32(temp4, 0);

                            // read common path suffix offset
                            R.BaseStream.Position = lnkinfostructure_start + 24;
                            R.Read(temp4, 0, 4);
                            CommonPathSuffixOffset = BitConverter.ToInt32(temp4, 0);

                            if (LinkInfoFlags[0] == '1') // we have a volumeid and local base path!
                            {
                                Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "we have a volumeid and local base path!\n"));
                                VolumeIDstructure_start = lnkinfostructure_start + VolumeIDOffset;
                                // lets goto the volumeID structre
                                // Read VolumeIDSize
                                R.BaseStream.Position = VolumeIDstructure_start;
                                R.Read(temp4, 0, 4);
                                VolumeIDSize = BitConverter.ToInt32(temp4, 0);

                                // read drive type
                                R.BaseStream.Position = VolumeIDstructure_start + 4;
                                R.Read(temp4, 0, 4);
                                int DriveType1num = BitConverter.ToInt32(temp4, 0);

                                switch (DriveType1num)
                                {
                                    case 0:
                                        DriveType1 = "Unknown"; break;
                                    case 1:
                                        DriveType1 = "No Root Directory"; break;
                                    case 2:
                                        DriveType1 = "Removable"; break;
                                    case 3:
                                        DriveType1 = "Fixed Media"; break;
                                    case 4:
                                        DriveType1 = "Remove (network)"; break;
                                    case 5:
                                        DriveType1 = "CD-ROM Drive"; break;
                                    case 6:
                                        DriveType1 = "RAM Disk"; break;
                                }
                                Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Drive type read\n"));

                                // read VolumeSerialNumber
                                R.BaseStream.Position = VolumeIDstructure_start + 8;
                                R.Read(temp4, 0, 4);
                                VolumeSerialNumber = bytestostring_littleendian(temp4);

                                // read VolumeLabelOffset
                                R.BaseStream.Position = VolumeIDstructure_start + 12;
                                R.Read(temp4, 0, 4);
                                VolumeLabelOffset = BitConverter.ToInt32(temp4, 0);

                                // read VolumeLabel
                                int tempor = VolumeIDstructure_start + VolumeLabelOffset;
                                R.BaseStream.Position = tempor;

                                int byte11 = 1;
                                string temp11 = "";
                                R.BaseStream.Position = tempor;
                                // we need to check the first byte as this is sometimes null
                                R.Read(temp4, 0, 1);
                                byte11 = BitConverter.ToInt16(temp4, 0);
                                // if the first byte isn't null then lets read the rest of the string
                                while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                {
                                    R.BaseStream.Position = tempor;
                                    R.Read(temp1, 0, 1);
                                    R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                    byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                    temp11 = System.Text.Encoding.Default.GetString(temp1);
                                    //MessageBox.Show(byte11.ToString());
                                    VolumeLabel = VolumeLabel + temp11;
                                    tempor++;
                                }
                                Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "VolumeLabel read\n"));

                                // now lets read the local base path
                                tempor = lnkinfostructure_start + LocalBasePathOffset;
                                R.BaseStream.Position = tempor;

                                byte11 = 1;
                                temp11 = "";
                                while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                {
                                    R.BaseStream.Position = tempor;
                                    R.Read(temp1, 0, 1);
                                    R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                    byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                    temp11 = System.Text.Encoding.Default.GetString(temp1);
                                    LocalBasePath = LocalBasePath + temp11;
                                    tempor++;
                                }
                                LinkedPath = LocalBasePath;
                                Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "LocalBasePath read\n"));
                            }
                            else
                            {
                                LocalBasePath = "";
                            }
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), " ", LinkInfoFlags, "LocalBasePath read\n"));

                            if (LinkInfoFlags.Length > 1) // then we have a common network relative link and path suffix
                            {
                                Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "we have a common network relative link and path suffix\n"));
                                string CommonPathSuffix = "";
                                if (LinkInfoFlags[1] == '1')
                                {
                                    // now lets go to this offset for the common network relative link
                                    int CommonNetworkRelativeLink = lnkinfostructure_start + CommonNetworkRelativeLinkOffset;
                                    R.BaseStream.Position = CommonNetworkRelativeLink;

                                    // read CommonNetworkRelativeLinkSize
                                    R.BaseStream.Position = CommonNetworkRelativeLink;
                                    R.Read(temp4, 0, 4);
                                    CommonNetworkRelativeLinkSize = BitConverter.ToInt32(temp4, 0);

                                    // read CommonNetworkRelativeLinkFlags
                                    R.BaseStream.Position = CommonNetworkRelativeLink + 4;
                                    R.Read(temp4, 0, 1);
                                    temp = BitConverter.ToInt32(temp4, 0); // convert bytes to number
                                    CommonNetworkRelativeLinkFlags = Convert.ToString(temp, 2); // convert number to binary
                                    // reverse the string
                                    char[] charArray2 = CommonNetworkRelativeLinkFlags.ToCharArray();
                                    Array.Reverse(charArray2);
                                    CommonNetworkRelativeLinkFlags = new string(charArray2);

                                    // read NetNameOffset
                                    R.BaseStream.Position = CommonNetworkRelativeLink + 8;
                                    R.Read(temp4, 0, 4);
                                    NetNameOffset = BitConverter.ToInt32(temp4, 0);

                                    // read DeviceNameOffset
                                    R.BaseStream.Position = CommonNetworkRelativeLink + 12;
                                    R.Read(temp4, 0, 4);
                                    DeviceNameOffset = BitConverter.ToInt32(temp4, 0);

                                    // read NetworkProviderType (maybe not needed)
                                    R.BaseStream.Position = CommonNetworkRelativeLink + 16;
                                    R.Read(temp4, 0, 4);
                                    NetworkProviderType = BitConverter.ToString(temp4, 0);

                                    // read NetName
                                    int tempor = CommonNetworkRelativeLink + NetNameOffset;
                                    R.BaseStream.Position = tempor;

                                    int byte11 = 1;
                                    string temp11 = "";
                                    while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                    {
                                        R.BaseStream.Position = tempor;
                                        R.Read(temp1, 0, 1);
                                        R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                        byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                        temp11 = System.Text.Encoding.Default.GetString(temp1);
                                        NetName = NetName + temp11;
                                        tempor++;
                                    }
                                    Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Netname read\n"));

                                    if (CommonNetworkRelativeLinkFlags[0] == '1') // we have a valid device!
                                    {
                                        Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Link file has a valid device name\n"));
                                        // read DeviceName
                                        tempor = CommonNetworkRelativeLink + DeviceNameOffset;
                                        R.BaseStream.Position = tempor;

                                        //we need to check for null straight away
                                        R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                        byte11 = BitConverter.ToInt16(temp4, 0); // check for null

                                        byte11 = 1;
                                        temp11 = "";
                                        while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                        {
                                            R.BaseStream.Position = tempor;
                                            R.Read(temp1, 0, 1);
                                            R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                            byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                            temp11 = System.Text.Encoding.Default.GetString(temp1);
                                            DeviceName = DeviceName + temp11;
                                            tempor++;
                                        }
                                        DeviceName = String.Concat(DeviceName, @"\");
                                        Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Device name read\n"));
                                    }
                                    else
                                    {
                                        DeviceName = "";
                                    }

                                    // now we go to the offset for the common path suffix
                                    tempor = lnkinfostructure_start + CommonPathSuffixOffset;
                                    R.BaseStream.Position = tempor;

                                    byte11 = 1;
                                    temp11 = "";
                                    while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                    {
                                        R.BaseStream.Position = tempor;
                                        R.Read(temp1, 0, 1);
                                        R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                        byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                        temp11 = System.Text.Encoding.Default.GetString(temp1);
                                        CommonPathSuffix = CommonPathSuffix + temp11;
                                        tempor++;
                                    }
                                    LinkedPath = DeviceName + LinkedPath + CommonPathSuffix;
                                    Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "FULL linked path read\n"));
                                }
                            }
                            else
                            {
                                NetName = "";
                                DeviceName = "";
                            }
                        }
                        Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "End of LNKINFO section\n"));

                        // read StringData
                        if (lnkflags[1] == '0') StringData_start = 78 + IDListSize; // as there is no LinkInfo structure
                        else StringData_start = 78 + IDListSize + LinkInfoSize; // as there is a LinkInfo structure, we need to go past this

                        int CurrentPosition;
                        CurrentPosition = StringData_start;

                        if (lnkflags[2] == '1') NameString = parseStringData(R, CurrentPosition, out CurrentPosition);
                        if (lnkflags[3] == '1') RelativePath = parseStringData(R, CurrentPosition, out CurrentPosition);
                        if (lnkflags[4] == '1') WorkingDir = parseStringData(R, CurrentPosition, out CurrentPosition);
                        if (lnkflags[5] == '1') CommandLineArgs = parseStringData(R, CurrentPosition, out CurrentPosition);
                        if (lnkflags[6] == '1') IconLocation = parseStringData(R, CurrentPosition, out CurrentPosition);

                        int BlockSize_extra;
                        // we need to parse the ExtraData section now
                        int endoflnkfile = (int)R.BaseStream.Length - 4; // the end of the file padded with 4 nulls
                        Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "End of LNK file is ", endoflnkfile.ToString(), "\n"));

                        while (R.BaseStream.Position < endoflnkfile)
                        {
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "StringData loop position\n"));
                            //first of all, lets read the ExtraData BlockSize
                            R.BaseStream.Position = CurrentPosition;
                            R.Read(temp4, 0, 4);
                            BlockSize_extra = BitConverter.ToInt32(temp4, 0);
                            // now we need to read the signature
                            // read sig
                            R.BaseStream.Position = CurrentPosition + 4;
                            R.Read(temp2, 0, 2);
                            Sig_extra = BitConverter.ToInt16(temp2, 0);
                            Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Signature is ", Sig_extra, "\n"));

                            string typeofblock = "";
                            int exit_now = 0;
                            switch (Sig_extra)
                            {
                                case 2:
                                    typeofblock = "ConsoleDataBlock";
                                    break;
                                case 4:
                                    typeofblock = "ConsoleFEDataBlock";
                                    break;
                                case 6:
                                    typeofblock = "DarwinDataBlock";
                                    break;
                                case 1:
                                    typeofblock = "EnvironmentVariableDataBlock";
                                    break;
                                case 7:
                                    typeofblock = "IconEnvironmentDataBlock";
                                    break;
                                case 11:
                                    typeofblock = "KnownFolderDataBlock";
                                    break;
                                case 9:
                                    typeofblock = "PropertyStoreDataBlock";
                                    break;
                                case 8:
                                    typeofblock = "ShimDataBlock";
                                    break;
                                case 5:
                                    typeofblock = "SpecialFolderDataBlock";
                                    break;
                                case 3:
                                    typeofblock = "TrackerDataBlock";
                                    // parse the NetBIOS name
                                    int tempor = CurrentPosition + 16;
                                    R.BaseStream.Position = tempor;

                                    int byte11 = 1;
                                    string temp11 = "";
                                    while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                    {
                                        Trace.Write(string.Concat(R.BaseStream.Position.ToString(), "Inside the tracker block netBIOS name\n"));
                                        R.BaseStream.Position = tempor;
                                        if (R.BaseStream.Position > endoflnkfile + 3) break; // we need this for carved LNKs
                                        R.Read(temp1, 0, 1);
                                        R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                                        byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                        temp11 = System.Text.Encoding.Default.GetString(temp1);
                                        NetBIOS = NetBIOS + temp11;
                                        tempor++;
                                    }
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "NetBIOS name parsed\n"));

                                    // we need this to get the current Volume/Object ID
                                    int VolumeID_offset = CurrentPosition + BlockSize_extra - 64;
                                    R.BaseStream.Position = VolumeID_offset;
                                    R.Read(temp16, 0, 16);
                                    VolumeID_current = bytestostring(temp16, null);
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Volume ID parsed\n"));
                                    // we need this to get the current Object ID
                                    R.BaseStream.Position = VolumeID_offset + 16;
                                    R.Read(temp16, 0, 16);
                                    ObjectID_current = bytestostring(temp16, null);
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Object ID parsed\n"));
                                    // extract the MAC address
                                    R.BaseStream.Position = VolumeID_offset + 26;
                                    R.Read(temp6, 0, 6);
                                    newmacaddr = bytestostring(temp6, "mac");

                                    // we need this to get the birth Volume/Object ID
                                    VolumeID_offset = CurrentPosition + BlockSize_extra - 32;
                                    R.BaseStream.Position = VolumeID_offset;
                                    R.Read(temp16, 0, 16);
                                    VolumeID_birth = bytestostring(temp16, null);
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Birth volume ID parsed\n"));
                                    // we need this to get the birth Object ID
                                    R.BaseStream.Position = VolumeID_offset + 16;
                                    R.Read(temp16, 0, 16);
                                    ObjectID_birth = bytestostring(temp16, null);
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Birth object ID parsed\n"));
                                    // extract the birth MAC address
                                    R.BaseStream.Position = VolumeID_offset + 26;
                                    R.Read(temp6, 0, 6);
                                    birthmacaddr = bytestostring(temp6, "mac");

                                    break;
                                case 12:
                                    typeofblock = "VistaAndAboveIDListDataBlock";
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Type of block is " + typeofblock + "\n"));
                                    break;
                                default:
                                    exit_now = 1;
                                    Trace.Write(String.Concat(R.BaseStream.Position.ToString() + ";" + i + ";" + "Not a valid block - end parsing NOW\n"));
                                    break;
                            }

                            if (exit_now == 1) { break; } // check for exit invalid link file
                            // move to the next extra data block
                            CurrentPosition = CurrentPosition + BlockSize_extra;
                            if (CurrentPosition == endoflnkfile) { break; } //for some reason we need this
                        }                 
                    }
                    else
                    {
                        lnkfilefalse_counter++;
                    }
                }
                catch (Exception e)
                {
                    Trace.Write("{0} Exception caught.", e.ToString());
                    MessageBox.Show(String.Concat("Error parsing .lnk file: " + Path.GetFileName(i)), "Error"); //e.ToString(),Path.GetFileName(i));
                    Trace.Flush();
                }
                finally // write data into database
                {
                    if (type == 1) // normal LNK file
                    {
                        //toUTClnkToolStripMenuItem.Visible = true;
                        gv.Rows.Add(Path.GetFileName(i), LinkedPath, CreationTime_lnkfile, AccessTime_lnkfile, WriteTime_lnkfile, CreationTime, AccessTime,
                            WriteTime, filesize, NetName, NetBIOS, DriveType1, VolumeSerialNumber, VolumeLabel, NameString, RelativePath,
                            WorkingDir, CommandLineArgs, VolumeID_current, ObjectID_current, newmacaddr, VolumeID_birth, ObjectID_current, birthmacaddr, md5hash);
                    }
                    else if (type == 2) // jump-list embedded file
                    {
                        //toUTCjllnkToolStripMenuItem.Visible = true;
                        gv.Rows.Add(dir_name, LinkedPath, CreationTime, AccessTime,
                        WriteTime, filesize, NetName, NetBIOS, DriveType1, VolumeSerialNumber, VolumeLabel, NameString, RelativePath,
                        WorkingDir, CommandLineArgs, VolumeID_current, ObjectID_current, newmacaddr, VolumeID_birth, ObjectID_current, birthmacaddr, md5hash);
                    }
                }
        }

        private void parsei30stream(Stream x, string i, DataTable gv)
        {
            Trace.Write(string.Concat(x.Length.ToString(), " Stream length\n"));

            // Define global vars
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[2];
            byte[] temp4 = new byte[4];
            byte[] temp8 = new byte[8];
            byte[] temp6 = new byte[6];
            byte[] temp16 = new byte[16];

            // Define our header variables
            int header, index_entry_offset, sizeof_entries, sizeof_entries_alloc, numberof_records;
            int updated_sequence_array_offset, sizeof_updated_sequence_array;
            long logfile_seq_num;

            // we need this for the "fix-up" values to be applied
            int update_seq_number;

            // Define our INDX variables
            int indx_record_start;
            long mftref = 0, parent_mftref;
            int sizeof_indx_entry, sizeof_stream;
            DateTime? Creation_Time = null;
            DateTime? Modified_Time = null;
            DateTime? Access_Time = null;
            DateTime? mft_record_change_time = null;
            long phy_sizeof_file, logical_sizeof_file, start_of_block;
            int filename_length;
            string embedded_filename = "", slack_space = "";

            using (BinaryReader R = new BinaryReader(x))
                try
                {
                    Trace.Write("Starting $I30 parsing\n");
                    // lets go from the start
                    R.BaseStream.Position = 0;
                    start_of_block = 0;

                    // read the header
                    R.Read(temp4, 0, 4);
                    header = BitConverter.ToInt32(temp4, 0); //convert to a 32 bit value

                    if (header == 1480871497) // decimal of string == INDX
                    {
                        Trace.Write("Valid $I30 file found\n");
                        // we have a valid $I30 header so lets go do stuff

                        int exit = 0;
                        while (exit < 1) // 0 = no, 1 = yes
                        {
                            R.BaseStream.Position = start_of_block;
                            start_of_block = R.BaseStream.Position;
                            Trace.Write(String.Concat(R.BaseStream.Position.ToString(), " Start of array\n"));

                            // read the header
                            R.Read(temp4, 0, 4);
                            header = BitConverter.ToInt32(temp4, 0); //convert to a 32 bit value
                            if (header == 1480871497) //valid INDX record
                            {
                                // read updated_sequence_array_offset
                                R.BaseStream.Position = start_of_block + 4;
                                R.Read(temp2, 0, 2);
                                updated_sequence_array_offset = BitConverter.ToInt16(temp2, 0);
                                Trace.Write(String.Concat(updated_sequence_array_offset, " Updated Seq Array Off.\n"));
                                // now we go to this offset and save the sequence number (the last two bytes of every block should be like this)
                                R.BaseStream.Position = start_of_block + updated_sequence_array_offset;
                                R.Read(temp2, 0, 2);
                                update_seq_number = BitConverter.ToInt16(temp2, 0);
                                // read size of updated_sequence_array
                                R.BaseStream.Position = start_of_block + 6;
                                R.Read(temp2, 0, 2);
                                sizeof_updated_sequence_array = BitConverter.ToInt16(temp2, 0);
                                Trace.Write(String.Concat(sizeof_updated_sequence_array, " Size of above\n"));

                                // now we have to read the updated sequence array and save it as an.. array!
                                R.BaseStream.Position = start_of_block + updated_sequence_array_offset + 2;
                                int[] seq_array = new int[sizeof_updated_sequence_array]; 
                                for (int counter = 0; counter < sizeof_updated_sequence_array; counter++)
                                {
                                    R.Read(temp2, 0, 2);
                                    seq_array[counter] = BitConverter.ToInt16(temp2, 0);
                                    //MessageBox.Show(string.Concat(update_seq_number, " should be ", seq_array[counter]));
                                }

                                //// now we need to go through the stream and edit all the fix-up values
                                //// I know its bad to edit a file in forensics but here we are only modifying the stream in memory
                                //long temppor = start_of_block;
                                //for (int counter = 0; counter < sizeof_updated_sequence_array; counter++)
                                //{
                                //    R.BaseStream.Position = temppor + 510; // to read the last two bytes in the sector
                                //    R.Read(temp2, 0, 2);
                                //    int temp = BitConverter.ToInt16(temp2, 0);
                                //    if (temp == update_seq_number)
                                //    {
                                //        BinaryWriter W = new BinaryWriter
                                //        MessageBox.Show(string.Concat("Do something! ", temp, " should be ", seq_array[counter]));
                                //    }
                                //}

                                // read log file seq. number
                                R.BaseStream.Position = start_of_block + 8;
                                R.Read(temp8, 0, 8);
                                logfile_seq_num = BitConverter.ToInt64(temp8, 0);
                                Trace.Write(String.Concat(logfile_seq_num, " log file seq num\n"));

                                // read index entry offset
                                R.BaseStream.Position = start_of_block + 24;
                                R.Read(temp4, 0, 4);
                                index_entry_offset = BitConverter.ToInt32(temp4, 0);
                                Trace.Write(String.Concat(index_entry_offset, " Index entry offset\n"));

                                // size of entries
                                R.BaseStream.Position = start_of_block + 28;
                                R.Read(temp4, 0, 4);
                                sizeof_entries = BitConverter.ToInt32(temp4, 0);
                                Trace.Write(String.Concat(sizeof_entries, " size of entries\n"));

                                // size of entries (allocated)
                                R.BaseStream.Position = start_of_block + 32;
                                R.Read(temp4, 0, 4);
                                sizeof_entries_alloc = BitConverter.ToInt32(temp4, 0);
                                Trace.Write(String.Concat(sizeof_entries_alloc, " sizeof entries allocated\n"));

                                int end_of_block = (int)Math.Ceiling((decimal)sizeof_entries_alloc / 512);
                                end_of_block = end_of_block * 512;

                                // lets go through all the ALLOCATED records
                                indx_record_start = (int)start_of_block + 64; // first record is located here
                                while (R.BaseStream.Position < (start_of_block + sizeof_entries))
                                {
                                    slack_space = "No";
                                    // now lets go parse the INDX records
                                    R.BaseStream.Position = indx_record_start;

                                    // read MFT ref
                                    R.Read(temp8, 0, 8);
                                    mftref = BitConverter.ToInt64(temp8, 0);
                                    Trace.Write(String.Concat(mftref, " MFT ref\n"));

                                    // read size of INDX entry
                                    R.BaseStream.Position = indx_record_start + 8;
                                    R.Read(temp2, 0, 2);
                                    sizeof_indx_entry = BitConverter.ToInt16(temp2, 0);
                                    Trace.Write(String.Concat(sizeof_indx_entry, " Size of index entry\n"));

                                    // read size of stream
                                    R.BaseStream.Position = indx_record_start + 10;
                                    R.Read(temp2, 0, 2);
                                    sizeof_stream = BitConverter.ToInt16(temp2, 0);
                                    Trace.Write(String.Concat(sizeof_stream, " size of stream\n"));

                                    // read parent MFT ref
                                    R.BaseStream.Position = indx_record_start + 16;
                                    R.Read(temp8, 0, 8);
                                    parent_mftref = BitConverter.ToInt64(temp8, 0);
                                    Trace.Write(String.Concat(parent_mftref, " Parent MFT ref\n"));

                                    // read times - making sure to check if they exist on 512 boundaries to that fixup values can be applied
                                    // 
                                    if ((indx_record_start + 24 + 8) % 512 == 0)
                                    {
                                        // exists on boundary, we must edit this hex before passing it to "ReadtargetLNKtime"
                                        // we need to see how far the boundary is...
                                        // first off we need to start at the 4096 boundary...
                                        int temp = ((indx_record_start + 24 + 8) / 4096); // this is to see how far along we are. for example 4608/4096 = 1.125. This is saved as 1 (as it is an int). So 1 * 4096 = 4096.
                                        temp = temp * 4096;
                                        // now we need to see how far we are along the 4096 sector..
                                        int unique_sec_number_inarray = ((indx_record_start - temp + 24 + 8) / 512 - 1);
                                        Creation_Time = ReadTargetLnkTime(indx_record_start + 24, R, temp8, "local", "yes", seq_array[unique_sec_number_inarray]);
                                    }
                                    else
                                    {
                                        Creation_Time = ReadTargetLnkTime(indx_record_start + 24, R, temp8, "local", "no", 0);
                                    }
                                    Trace.Write(String.Concat(Creation_Time, " Creation\n"));

                                    if ((indx_record_start + 32 + 8) % 512 == 0)
                                    {
                                        // exists on boundary, we must edit this hex before passing it to "ReadtargetLNKtime"
                                        // we need to see how far the boundary is...
                                        // first off we need to start at the 4096 boundary...
                                        int temp = ((indx_record_start + 32 + 8) / 4096); // this is to see how far along we are. for example 4608/4096 = 1.125. This is saved as 1 (as it is an int). So 1 * 4096 = 4096.
                                        temp = temp * 4096;
                                        // now we need to see how far we are along the 4096 sector..
                                        int unique_sec_number_inarray = ((indx_record_start - temp + 32 + 8) / 512 - 1);
                                        Modified_Time = ReadTargetLnkTime(indx_record_start + 32, R, temp8, "local", "yes", seq_array[unique_sec_number_inarray]);
                                    }
                                    else
                                    {
                                        Modified_Time = ReadTargetLnkTime(indx_record_start + 32, R, temp8, "local", "no", 0);
                                    }
                                    Trace.Write(String.Concat(Modified_Time, " Modified\n"));

                                    mft_record_change_time = ReadTargetLnkTime(indx_record_start + 40, R, temp8, "local", "no", 0);
                                    Access_Time = ReadTargetLnkTime(indx_record_start + 48, R, temp8, "local", "no", 0);

                                    // read physical size of file
                                    R.BaseStream.Position = indx_record_start + 56;
                                    R.Read(temp8, 0, 8);
                                    phy_sizeof_file = BitConverter.ToInt64(temp8, 0);

                                    // read logical size of file
                                    R.BaseStream.Position = indx_record_start + 64;
                                    R.Read(temp8, 0, 8);
                                    logical_sizeof_file = BitConverter.ToInt64(temp8, 0);
                                    Trace.Write(String.Concat(logical_sizeof_file, " Logical size\n"));

                                    // read filename length
                                    R.BaseStream.Position = indx_record_start + 80;
                                    R.Read(temp2, 0, 1);
                                    filename_length = BitConverter.ToInt16(temp2, 0);
                                    filename_length = filename_length * 2; // as we are reading the values in unicode
                                    Trace.Write(String.Concat(filename_length, " File name length\n"));

                                    // go read filename
                                    // read entry name
                                    embedded_filename = "";
                                    string temp11 = "";
                                    int tempor = indx_record_start + 82;
                                    while (tempor < indx_record_start + 82 + filename_length)
                                    {
                                        R.BaseStream.Position = tempor;
                                        R.Read(temp1, 0, 1);
                                        temp11 = System.Text.Encoding.Default.GetString(temp1);
                                        embedded_filename = embedded_filename + temp11;
                                        tempor = tempor + 2; // skip the null-delimited
                                    }

                                    int end_of_record = (int)Math.Ceiling((decimal)R.BaseStream.Position / 8);
                                    end_of_record = end_of_record * 8;

                                    // put data in the database
                                    gv.Rows.Add(Path.GetFileName(i), embedded_filename, slack_space, mftref, parent_mftref, Creation_Time,
                                        Modified_Time, Access_Time, mft_record_change_time, phy_sizeof_file, logical_sizeof_file);

                                    // move the stream on
                                    if (sizeof_indx_entry > 82)
                                    {
                                        indx_record_start = indx_record_start + sizeof_indx_entry;
                                    }
                                    else if (sizeof_indx_entry <= 0)
                                    {
                                        indx_record_start = end_of_record;
                                    }
                                }

                                int end_of_allocated = (int)Math.Ceiling((decimal)R.BaseStream.Position / 8);
                                end_of_allocated = end_of_allocated * 8;

                                // now lets attempt to parse the records in UNALLOCATED
                                //MessageBox.Show(String.Concat("Position start of unalloc ", end_of_allocated.ToString()));

                                indx_record_start = end_of_allocated; // move to the unallocated space
                                R.BaseStream.Position = indx_record_start;
                                int inc = 0;
                                while (R.BaseStream.Position < (start_of_block + end_of_block))
                                {
                                    Trace.Write(String.Concat("Position: ", R.BaseStream.Position.ToString(), "\n"));

                                    //first, we did to check this record has valid data! As it can be corrupt... best way to check this is with the 4 date/time stamps
                                    // read times, we need to redefine these for some reason
                                    DateTime Creation = ReadTargetLnkTime_noq(indx_record_start + 24, R, temp8, "local");
                                    DateTime Modified = ReadTargetLnkTime_noq(indx_record_start + 32, R, temp8, "local");
                                    DateTime mft_record = ReadTargetLnkTime_noq(indx_record_start + 40, R, temp8, "local");
                                    DateTime Access = ReadTargetLnkTime_noq(indx_record_start + 48, R, temp8, "local");
                                    DateTime comp = new DateTime(1990, 1, 1, 0, 0, 0);

                                    if (DateTime.Compare(Creation, comp) + DateTime.Compare(Modified, comp) + DateTime.Compare(mft_record, comp) + DateTime.Compare(Access, comp) == 4)
                                    {
                                        // now lets go parse the INDX records
                                        R.BaseStream.Position = indx_record_start;
                                        slack_space = String.Concat("Yes: at offset ", R.BaseStream.Position.ToString("X"));

                                        // read MFT ref
                                        R.Read(temp8, 0, 8);
                                        mftref = BitConverter.ToInt64(temp8, 0);
                                        Trace.Write(String.Concat(mftref, " MFT ref\n"));

                                        // read size of INDX entry
                                        R.BaseStream.Position = indx_record_start + 8;
                                        R.Read(temp2, 0, 2);
                                        sizeof_indx_entry = BitConverter.ToInt16(temp2, 0);
                                        Trace.Write(String.Concat(sizeof_indx_entry, " Size of index entry\n"));

                                        // read size of stream
                                        R.BaseStream.Position = indx_record_start + 10;
                                        R.Read(temp2, 0, 2);
                                        sizeof_stream = BitConverter.ToInt16(temp2, 0);
                                        Trace.Write(String.Concat(sizeof_stream, " size of stream\n"));

                                        // read parent MFT ref
                                        R.BaseStream.Position = indx_record_start + 16;
                                        R.Read(temp8, 0, 8);
                                        parent_mftref = BitConverter.ToInt64(temp8, 0);
                                        Trace.Write(String.Concat(parent_mftref, " Parent MFT ref\n"));

                                        // read times
                                        Creation_Time = ReadTargetLnkTime(indx_record_start + 24, R, temp8, "local", "no", 0);
                                        Trace.Write(String.Concat(Creation_Time, " Creation\n"));
                                        Modified_Time = ReadTargetLnkTime(indx_record_start + 32, R, temp8, "local", "no", 0);
                                        Trace.Write(String.Concat(Modified_Time, " Modified\n"));
                                        mft_record_change_time = ReadTargetLnkTime(indx_record_start + 40, R, temp8, "local", "no", 0);
                                        Access_Time = ReadTargetLnkTime(indx_record_start + 48, R, temp8, "local", "no", 0);

                                        // read physical size of file
                                        R.BaseStream.Position = indx_record_start + 56;
                                        R.Read(temp8, 0, 8);
                                        phy_sizeof_file = BitConverter.ToInt64(temp8, 0);

                                        // read logical size of file
                                        R.BaseStream.Position = indx_record_start + 64;
                                        R.Read(temp8, 0, 8);
                                        logical_sizeof_file = BitConverter.ToInt64(temp8, 0);
                                        Trace.Write(String.Concat(logical_sizeof_file, " Logical size\n"));

                                        // read filename length
                                        R.BaseStream.Position = indx_record_start + 80;
                                        R.Read(temp2, 0, 1);
                                        filename_length = BitConverter.ToInt16(temp2, 0);
                                        filename_length = filename_length * 2; // as we are reading the values in unicode
                                        Trace.Write(String.Concat(filename_length, " File name length\n"));

                                        // go read filename
                                        // read entry name
                                        embedded_filename = "";
                                        string temp11 = "";
                                        int tempor = indx_record_start + 82;
                                        while (tempor < indx_record_start + 82 + filename_length)
                                        {
                                            R.BaseStream.Position = tempor;
                                            R.Read(temp1, 0, 1);
                                            temp11 = System.Text.Encoding.Default.GetString(temp1);
                                            embedded_filename = embedded_filename + temp11;
                                            tempor = tempor + 2; // skip the null-delimited
                                        }
                                        Trace.Write(String.Concat(embedded_filename, " File name\n"));

                                        int end_of_record = (int)Math.Ceiling((decimal)R.BaseStream.Position / 8);
                                        end_of_record = end_of_record * 8;

                                        // put data in the database
                                        gv.Rows.Add(Path.GetFileName(i), embedded_filename, slack_space, mftref, parent_mftref, Creation_Time,
                                            Modified_Time, Access_Time, mft_record_change_time, phy_sizeof_file, logical_sizeof_file);

                                        // move the stream on
                                        if (sizeof_indx_entry > 82)
                                        {
                                            indx_record_start = indx_record_start + sizeof_indx_entry;
                                        }
                                        else
                                        {
                                            indx_record_start = end_of_record;
                                        }
                                        inc++;
                                    }
                                    else
                                    {
                                        indx_record_start = indx_record_start + 8;
                                    }
                                }

                                // move onto the next block
                                start_of_block = start_of_block + (long)end_of_block;
                                if (start_of_block >= x.Length)
                                {
                                    exit = 1;
                                }
                            }
                            else
                            {
                                start_of_block = start_of_block + 8;
                                if (start_of_block >= x.Length)
                                {
                                    exit = 1;
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Trace.Write("{0} Exception caught.", e.ToString());
                    //MessageBox.Show(String.Concat("Error parsing $I30 file: " + Path.GetFileName(i)), "Error"); //e.ToString(),Path.GetFileName(i));
                    Trace.Flush();
                }
                finally // write data into database
                {
                    
                }
        }

        private void parsedestliststream(Stream x, DataTable gv, int dircount)
        {
            dircount--; // we don't need to count the destlist node
            using (BinaryReader R = new BinaryReader(x))
                try
                {
                    int temppos = 32; // move past the header
                    for (int count1 = 0; count1 < dircount; count1++)
                    {
                        // declare our file times and vars
                        byte[] temp1 = new byte[1];
                        byte[] temp2 = new byte[2];
                        byte[] temp4 = new byte[4];
                        byte[] temp8 = new byte[8];
                        DateTime? embeddedtime_utc = null, embeddedtime_local = null;
                        string netBIOS = "";
                        string data = "";
                        R.BaseStream.Position = temppos;

                        int byte11 = 1;
                        string temp11 = "";
                        int tempor = temppos + 72;
                        R.BaseStream.Position = temppos + 72;
                        // we need to check the first byte as this is sometimes null
                        R.Read(temp4, 0, 1);
                        byte11 = BitConverter.ToInt16(temp4, 0);
                        // if the first byte isn't null then lets read the rest of the string
                        while (byte11 != 0) // save UNC path as a string, stop when you get to null
                        {
                            R.BaseStream.Position = tempor;
                            R.Read(temp1, 0, 1);
                            R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                            byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                            temp11 = System.Text.Encoding.Default.GetString(temp1);
                            //MessageBox.Show(byte11.ToString());
                            netBIOS = netBIOS + temp11;
                            tempor++;
                        }

                        // read stream number
                        R.BaseStream.Position = temppos + 88;
                        R.Read(temp1, 0, 1);
                        string streamnumber = BitConverter.ToString(temp1, 0);

                        // read embedded time
                        embeddedtime_local = ReadTargetLnkTime(temppos + 100, R, temp8, "local", "no", 0);
                        embeddedtime_utc = ReadTargetLnkTime(temppos + 100, R, temp8, "utc", "no", 0);

                        // read number of characters for the data string
                        R.BaseStream.Position = temppos + 112;
                        R.Read(temp2, 0, 2);
                        int char_num = BitConverter.ToInt16(temp2, 0);
                        char_num = char_num * 2; // number of unicode values

                        temp11 = "";
                        tempor = temppos + 114;
                        R.BaseStream.Position = temppos + 114;
                        // we need to check the first byte as this is sometimes null
                        R.Read(temp4, 0, 1);
                        byte11 = BitConverter.ToInt16(temp4, 0);
                        // if the first byte isn't null then lets read the rest of the string
                        for (int count = 0; count < char_num; count = count + 2)
                        {
                            R.BaseStream.Position = tempor;
                            R.Read(temp1, 0, 1);
                            R.Read(temp4, 0, 1); // we have to read this into a 4 byte array (there is no ToInt8)
                            byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                            temp11 = System.Text.Encoding.Default.GetString(temp1);
                            //MessageBox.Show(byte11.ToString());
                            data = data + temp11;
                            tempor = tempor + 2;
                        }

                        gv.Rows.Add(streamnumber, netBIOS, embeddedtime_local, embeddedtime_utc, data);
                        temppos = temppos + 114 + char_num;
                    }
                }
                finally
                {
                }
        }

        private void parsei30_setuptable(DataTable x, Panel panel)
        {
            tabControl_main.SelectedTab = tabControl_main.TabPages[3];
            // Make the $I30 panel visible.
            panel.Visible = true;
            dataGridView_i30.Visible = false;
            statuslabel_i30_filesparsed.Text = "";
            statuslabel_i30_timetaken.Text = "";

            // Create the columns.
            x.Columns.Add("$I30 File Name", typeof(string));
            x.Columns.Add("Embedded File Name", typeof(string));
            x.Columns.Add("Slack Record", typeof(string));
            x.Columns.Add("MFT Ref", typeof(long));
            x.Columns.Add("Parent Dir", typeof(long));
            x.Columns.Add("Creation Time (Local)", typeof(DateTime));
            x.Columns.Add("Last Modified Time (Local)", typeof(DateTime));
            x.Columns.Add("Last Access Time (Local)", typeof(DateTime));
            x.Columns.Add("MFT Record Change Time (Local)", typeof(DateTime));
            x.Columns.Add("Physical File Size (Bytes)", typeof(long));
            x.Columns.Add("Logical File Size (Bytes)", typeof(long));
        }

        private void parsejl_setuptable(DataTable x, Panel panel)
        {
            tabControl_main.SelectedTab = tabControl_main.TabPages[2];
            // Make the .jl panel visible.
            panel.Visible = true;

            // create the columns
            x.Columns.Add("FileName", typeof(string));
            x.Columns.Add("Application", typeof(string));
            x.Columns.Add("MD5 Hash", typeof(string));
            x.Columns.Add("FullPath", typeof(string));
        }

        private void parsejl_finalisetable(DataTable datatable, DataGridView gridview, Panel panel)
        {
            // Set the gridview datasource.
            gridview.DataSource = datatable;
            this.dataGridjlinfo.Columns["FullPath"].Visible = false;

            // Sets the formatting of the grid.
            for (int i = 0; i < dataGridjlinfo.Columns.Count; i++)
            {
                int colw = dataGridjlinfo.Columns[i].Width;
                dataGridjlinfo.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                dataGridjlinfo.Columns[i].Width = colw;
            }
            gridview.Refresh();
            panel.Visible = true;
            splitContainerjl.Panel2Collapsed = true;
        }

        private void parsejumplist_dowork(string[] j)
        {
            //start the clock
            Stopwatch stopwatch1 = new Stopwatch();
            stopwatch1.Start();

            // create, and setup the table for the embedded link info
            DataTable lnkinfo = new DataTable("lnkinfo");
            parselnk_setuptable(lnkinfo, null, "embedded lnk");

            // create, and setup the table for the destlist info
            DataTable destlistinfo = new DataTable("destlistinfo");
            // create the columns for destlist
            destlistinfo.Columns.Add("Stream No.", typeof(string));
            destlistinfo.Columns.Add("Net BIOS", typeof(string));
            destlistinfo.Columns.Add("Embedded Time (Local)", typeof(DateTime));
            destlistinfo.Columns.Add("Embedded Time (UTC)", typeof(DateTime));
            destlistinfo.Columns.Add("Data", typeof(string));

            // define our variables
            int jlfilefalse_counter = 0, jlfiletrue_counter = 0;
            uint header;
            int first_dir_sector = 0, num_sat_sectors = 0, sector_size = 0, first_short_sector, num_miniFAT_sectors, sector_size_ministream = 0;
            byte[] temp4 = new byte[4];
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[2];
            byte[] temp8 = new byte[8];
            byte[] temp64 = new byte[64];
            byte[] temp512 = new byte[512];
            byte[][] streams = new byte[20][];
            int dir_entries_count = 0;

            // lets quickly check all the file headers so the progress bar reports well
            foreach (string i in j)
            {
                if (Path.GetExtension(i) == ".automaticDestinations-ms")
                {
                    using (BinaryReader R = new BinaryReader(File.Open(i, FileMode.Open, FileAccess.Read, FileShare.Read)))
                    try
                    {
                        //check header string to see if it is a valid pf file
                        R.BaseStream.Position = 0;
                        R.Read(temp2, 0, 2);
                        header = BitConverter.ToUInt16(temp2, 0);

                        if (header == 53200)
                        {
                            jlfiletrue_counter++;

                            // read size of sectors
                            R.BaseStream.Position = 30;
                            R.Read(temp2, 0, 2);
                            int SectorShift = BitConverter.ToInt16(temp2, 0);
                            if (SectorShift == 9)
                            { sector_size = 512; }
                            else if (SectorShift == 76)
                            { sector_size = 4096; }

                            // read sector size of the mini stream
                            R.BaseStream.Position = 32;
                            R.Read(temp2, 0, 2);
                            sector_size_ministream = BitConverter.ToInt16(temp2, 0);
                            double sector_size_ministream1 = Math.Pow(2, sector_size_ministream);

                            // read number of sat sectors
                            R.BaseStream.Position = 44;
                            R.Read(temp4, 0, 4);
                            num_sat_sectors = BitConverter.ToInt32(temp4, 0);

                            // first directory sector location
                            R.BaseStream.Position = 48;
                            R.Read(temp4, 0, 4);
                            first_dir_sector = BitConverter.ToInt32(temp4, 0);

                            // First short-sector location
                            R.BaseStream.Position = 60;
                            R.Read(temp4, 0, 4);
                            first_short_sector = BitConverter.ToInt32(temp4, 0);

                            // Number of short-sector sectors
                            R.BaseStream.Position = 64;
                            R.Read(temp4, 0, 4);
                            num_miniFAT_sectors = BitConverter.ToInt32(temp4, 0);

                            // there is no DIFAT sectors in jump-list files                          

                            //lets go through the Sector allocation table
                            int temppos = 512;
                            int[] satarray = new int[128];
                            R.BaseStream.Position = temppos;
                            int endofsector = temppos + 512;
                            for (int x = 0; R.BaseStream.Position < endofsector; x++)
                            {
                                R.BaseStream.Position = temppos;
                                R.Read(temp4, 0, 4);
                                satarray[x] = BitConverter.ToInt32(temp4, 0);
                                if (satarray[x] == -1) { break; }
                                temppos = temppos + 4;
                            }

                            //we need to get the allocation for each type of entry (directory, short-sector chain, stream data etc)
                            int[][] sector_allocation = new int[50][];
                            //sector_allocation[0] is the directory chain, type index 0
                            sector_allocation[0] = new int[1000];
                            //sector_allocation[1] is the short-sector chain, type index 1
                            sector_allocation[1] = new int[1000];
                            //sector_allocation[2] is stream 1 data, type index 2
                            sector_allocation[2] = new int[5000];

                            //get the sector allocation for the directory entries
                            int index = first_dir_sector, subtype_index = 1;
                            sector_allocation[0][0] = first_dir_sector;
                            while (index > 0)
                            {
                                sector_allocation[0][subtype_index] = satarray[index];
                                //MessageBox.Show(sector_allocation[0][subtype_index].ToString());
                                if (satarray[index] > 0)
                                {
                                    index = satarray[index];
                                }
                                else if (satarray[index] < 0) { break; }
                                subtype_index++;
                            }

                            //get the sector allocation for the short-sector entries
                            index = first_short_sector; subtype_index = 1;
                            sector_allocation[1][0] = first_short_sector;
                            while (index > 0)
                            {
                                sector_allocation[1][subtype_index] = satarray[index];
                                if (satarray[index] > 0)
                                {
                                    index = satarray[index];
                                }
                                else if (satarray[index] < 0) { break; }
                                subtype_index++;
                            }

                            //get the sector allocation for the user-defined streams
                            int sector_count_streams = 1;
                            index = 3; subtype_index = 1;
                            sector_allocation[2][0] = 3;
                            while (index > 0)
                            {
                                sector_allocation[2][subtype_index] = satarray[index];
                                if (satarray[index] > 0)
                                {
                                    index = satarray[index];
                                }
                                else if (satarray[index] < 0) { break; }
                                subtype_index++;
                                sector_count_streams++;
                            }

                            //now we must split up this stream into addressable sectors
                            int addressable_stream_sectors = (sector_count_streams * 512) / (int)sector_size_ministream1;
                            int[] ministream_sectors_position = new int[addressable_stream_sectors + 1];
                            int k = 0;
                            for (int x = 0; sector_allocation[2][x] > 0; x++)
                            {
                                temppos = (sector_allocation[2][x] + 1) * sector_size;
                                int directory_entries_start_end = temppos + 512;
                                R.BaseStream.Position = temppos;
                                while (R.BaseStream.Position < directory_entries_start_end)
                                {
                                    ministream_sectors_position[k] = (int)R.BaseStream.Position;
                                    temppos = temppos + 64;
                                    R.BaseStream.Position = temppos;
                                    k++;
                                }
                            }

                            //get the short-sector allocation
                            int[] shortsatarray = new int[1000];
                            int inc = 0;
                            //lets go through the Short-Sector allocation table
                            for (int x = 0; sector_allocation[1][x] > 0; x++)
                            {
                                temppos = (sector_allocation[1][x] + 1) * sector_size;
                                R.BaseStream.Position = temppos;
                                endofsector = temppos + 512;
                                while (R.BaseStream.Position < endofsector)
                                {
                                    R.BaseStream.Position = temppos;
                                    R.Read(temp4, 0, 4);
                                    if (BitConverter.ToInt32(temp4, 0) == -1) { break; }
                                    shortsatarray[inc] = BitConverter.ToInt32(temp4, 0);
                                    //MessageBox.Show(shortsatarray[inc].ToString());
                                    temppos = temppos + 4;
                                    inc++;
                                }
                            }

                            //lets now go to the directory and read all the entries
                            // lets quickly count the number of directory entries

                            for (int x = 0; sector_allocation[0][x] > 0; x++)
                            {
                                temppos = (sector_allocation[0][x] + 1) * sector_size;
                                int directory_entries_start_end = temppos + 512;
                                R.BaseStream.Position = temppos;
                                while (R.BaseStream.Position < directory_entries_start_end)
                                {
                                    R.BaseStream.Position = temppos + 66;
                                    R.Read(temp2, 0, 1);
                                    int object_type = BitConverter.ToInt16(temp2, 0);
                                    if (object_type == 2)
                                    {
                                        dir_entries_count++;
                                    }
                                    temppos = temppos + 128;
                                }
                            }

                            // now lets go through these and populate the tree view
                            treeViewjl.Nodes.Clear();
                            treeViewjl.BeginUpdate();
                            int node_number = 0;
                            TreeNode[] treenode_childarray = new TreeNode[dir_entries_count];
                            string root_name = "";

                            // lets go through all of the directory sectors
                            for (int x = 0; sector_allocation[0][x] > 0; x++)
                            {
                                temppos = (sector_allocation[0][x] + 1) * sector_size;
                                int directory_entries_start_end = temppos + 512;
                                R.BaseStream.Position = temppos;
                                while (temppos < directory_entries_start_end)
                                {
                                    R.BaseStream.Position = temppos;
                                    //if (R.BaseStream.Position == directory_entries_start_end) { break; } // as we set the position above, we need to check it
                                    // read entry name
                                    int byte11 = 1;
                                    string dir_entry_name = "";
                                    string temp11 = "";
                                    int tempor = temppos;
                                    // we need to check the first byte as this is sometimes null
                                    R.Read(temp4, 0, 2);
                                    byte11 = BitConverter.ToInt16(temp4, 0);
                                    // if the first byte isn't null then lets read the rest of the string
                                    while (byte11 != 0) // save UNC path as a string, stop when you get to null
                                    {
                                        R.BaseStream.Position = tempor;
                                        R.Read(temp1, 0, 1);
                                        R.Read(temp4, 0, 2); // we have to read this into a 4 byte array (there is no ToInt8)
                                        byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                        temp11 = System.Text.Encoding.Default.GetString(temp1);
                                        dir_entry_name = dir_entry_name + temp11;
                                        tempor = tempor + 2; //unicode here
                                    }
                                    if (dir_entry_name == "") { break; } // if the directory name is blank then we have reached the last directory name

                                    //read the object type and put these in the tree view
                                    R.BaseStream.Position = temppos + 66;
                                    R.Read(temp2, 0, 1);
                                    int object_type = BitConverter.ToInt16(temp2, 0);
                                    if (object_type == 5)
                                    {
                                        root_name = dir_entry_name;
                                    }
                                    else if (object_type == 2)
                                    {
                                        //read the sector ID for the first sector/short sector of the stream
                                        R.BaseStream.Position = temppos + 116;
                                        R.Read(temp4, 0, 4);
                                        int start_stream_sector_id = BitConverter.ToInt32(temp4, 0);
                                        //read the size of the stream
                                        R.BaseStream.Position = temppos + 120;
                                        R.Read(temp4, 0, 4);
                                        int size_of_stream = BitConverter.ToInt32(temp4, 0);
                                        //int size_of_stream_roundedup = ((size_of_stream / 512) + 1) * 512;
                                        //save this in the tree view
                                        treenode_childarray[node_number] = new TreeNode(string.Concat("ID ", dir_entry_name, ": ", "Size: ", size_of_stream));
                                        node_number++;

                                        //now lets go get the user-data streams and save them
                                        int temp3 = start_stream_sector_id;
                                        byte[] stream = new byte[size_of_stream];
                                        int temp5 = 0;
                                        while (shortsatarray[temp3] > 0)
                                        {
                                            R.BaseStream.Position = ministream_sectors_position[temp3];
                                            R.Read(stream, temp5, 64);
                                            temp3 = shortsatarray[temp3]; // go to the next sector number
                                            temp5 = temp5 + 64; // move the temporary location for the stream
                                        }

                                        Stream s = new MemoryStream(stream);
                                        //create a the stream in memory so we can access it
                                        if (dir_entry_name != "DestList")
                                        {
                                            parselnkstream(s, i, lnkinfo, 2, dir_entry_name);
                                            File.WriteAllBytes("stream-ex.stream", stream);
                                        }
                                        else if (dir_entry_name == "DestList")
                                        {
                                            parsedestliststream(s, destlistinfo, dir_entries_count);
                                        }
                                    }
                                    temppos = temppos + 128;
                                }
                            }
                            TreeNode treeNode = new TreeNode(root_name, treenode_childarray);
                            treeViewjl.Nodes.Add(treeNode);
                            treeViewjl.ExpandAll();
                            treeViewjl.EndUpdate();
                        }
                        else { jlfilefalse_counter++; }
                    }
                    catch (Exception e)
                    {
                        Trace.Write("{0} Exception caught.", e.ToString());
                        MessageBox.Show("Error parsing JL file"); //e.ToString(),Path.GetFileName(i));
                        Trace.Flush();
                    }
                    finally { }
                }
                else
                {
                    // something here?
                }
            }

            if (jlfilefalse_counter > 0)
            {
                MessageBox.Show(String.Concat(jlfilefalse_counter, " invalid jump list files found"), "Error");
            }

            statuslabel_jl_filesparsed.Text = String.Concat((dir_entries_count - 1), " embedded LNK files parsed.");

            //finalise table
            parselnk_finalisetable(lnkinfo, dataGridViewjl_lnk, null);
            this.dataGridViewjl_lnk.Columns["Creation Time (local)"].Visible = true;
            this.dataGridViewjl_lnk.Columns["Access Time (local)"].Visible = true;
            this.dataGridViewjl_lnk.Columns["Written Time (local)"].Visible = true;

            dataGridViewjl_destlist.DataSource = destlistinfo; // set the gridview datasource
            dataGridViewjl_destlist.Columns["Embedded Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            dataGridViewjl_destlist.Columns["Embedded Time (UTC)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";

            stopwatch1.Stop();
            string timetaken = stopwatch1.Elapsed.TotalSeconds.ToString();
            statuslabel_jl_timetaken.Text = String.Concat("Take taken: ", timetaken, " seconds.");

            toUTCToolStripMenuItem_jl.Visible = true;
        }

        private void parsepf_setuptable(DataTable datatable, Panel panel)
        {
            tabControl_main.SelectedTab = tabControl_main.TabPages[1];
            panel.Visible = true;
            dataGridview_pfinfo.Visible = false;
            statuslabel_pf_timetaken.Text = "";
            statuslabel_pf_filesparsed.Text = "";

            // create the columns
            datatable.Columns.Add("FileName", typeof(string));
            datatable.Columns.Add("Boot Process Name", typeof(string));
            datatable.Columns.Add("Hash Value", typeof(string));
            datatable.Columns.Add("Last Run Time (Local)", typeof(DateTime));
            datatable.Columns.Add("Run Count", typeof(int));
            datatable.Columns.Add("Version", typeof(string));
            datatable.Columns.Add("Volume Serial", typeof(string));
            datatable.Columns.Add("Volume Created Date (Local)", typeof(DateTime));
            datatable.Columns.Add("MD5 Hash", typeof(string));
            datatable.Columns.Add("FullPath", typeof(string));
        }

        private int parsepf_dowork(string[] selected_folder, DataTable datatable)
        {
            // define our variables
            int pffilefalse_counter = 0, pffiletrue_counter = 0, version, header, last_run_time_pos = 0, last_run_count_pos = 0;
            int pfruncount;
            string pf_version = "";
            byte[] temp4 = new byte[4];
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[2];
            byte[] temp8 = new byte[8];
            DateTime LastRunTime_local;

            // lets go through all the files one by one
            foreach (string i in selected_folder)
            {
                if (Path.GetExtension(i) == ".pf")
                {
                    statuslabel_pf_filebeingparsed.Text = String.Concat("Currently parsing: ", Path.GetFileName(i));
                    string md5hash = GetMD5HashFromFile(i);
                    using (BinaryReader R = new BinaryReader(File.Open(i, FileMode.Open, FileAccess.Read, FileShare.Read)))
                    try
                    {
                        //check header string to see if it is a valid pf file
                        R.BaseStream.Position = 4;
                        R.Read(temp4, 0, 4);
                        header = BitConverter.ToInt32(temp4, 0);
                        if (header == 1094927187)
                        {
                            pffiletrue_counter++;
                            R.BaseStream.Position = 0; // lets go from the start
                            //parse information from the header structure
                            //version number
                            R.Read(temp4, 0, 4);
                            version = BitConverter.ToInt32(temp4, 0);

                            // set the positions of the Last Run Time (Local) and count
                            if (version == 17) //this is xp
                            {
                                last_run_time_pos = 120;
                                last_run_count_pos = 144;
                                pf_version = "XP";
                            }
                            else if (version == 23) //this is vista/7
                            {
                                last_run_time_pos = 128;
                                last_run_count_pos = 152;
                                pf_version = "Vista / 7";
                            }

                            // read bootprocess name
                            string bootprocess = "";
                            int tempor = 16;
                            R.BaseStream.Position = tempor;

                            int byte11 = 1;
                            string temp11 = "";
                            R.BaseStream.Position = tempor;

                            // if the first byte isn't null then lets read the rest of the string
                            while (byte11 != 0) // save name as a string, stop when you get to null
                            {
                                R.BaseStream.Position = tempor;
                                R.Read(temp1, 0, 1);
                                R.Read(temp4, 0, 2); // we have to read this into a 4 byte array (there is no ToInt8)
                                byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                temp11 = System.Text.Encoding.Default.GetString(temp1);
                                bootprocess = bootprocess + temp11;
                                tempor = tempor + 2; // we are reading a unicode value here
                            }

                            //PF hash value
                            string pfhashvalue;
                            R.BaseStream.Position = 76;
                            R.Read(temp4, 0, 4);
                            pfhashvalue = bytestostring_littleendian(temp4);

                            //get Last Run Time (Local)
                            R.BaseStream.Position = last_run_time_pos;
                            R.Read(temp8, 0, 8);
                            LastRunTime_local = DateTime.FromFileTime(BitConverter.ToInt64(temp8, 0));

                            //get run count
                            R.BaseStream.Position = last_run_count_pos;
                            R.Read(temp4, 0, 4);
                            pfruncount = BitConverter.ToInt32(temp4, 0);

                            //get file ref offset
                            R.BaseStream.Position = 100;
                            R.Read(temp4, 0, 4);
                            int file_ref_offset = BitConverter.ToInt32(temp4, 0);

                            //get file ref length
                            R.BaseStream.Position = 104;
                            R.Read(temp4, 0, 4);
                            int file_ref_length = BitConverter.ToInt32(temp4, 0);

                            //get volume information offset
                            R.BaseStream.Position = 108;
                            R.Read(temp4, 0, 4);
                            int vol_info_offset = BitConverter.ToInt32(temp4, 0);
                            //lets go get this information
                            R.BaseStream.Position = vol_info_offset + 8;
                            R.Read(temp8, 0, 8);
                            DateTime vol_create_time_local = DateTime.FromFileTime(BitConverter.ToInt64(temp8, 0));
                            R.BaseStream.Position = vol_info_offset + 16;
                            R.Read(temp4, 0, 4);
                            string vol_serial = bytestostring_littleendian(temp4);

                            // write data into database
                            datatable.Rows.Add(Path.GetFileName(i), bootprocess, pfhashvalue, LastRunTime_local, pfruncount, pf_version, 
                                vol_serial, vol_create_time_local, md5hash, i);
                        }

                        else if (header != 1094927187)
                        {
                            pffilefalse_counter++;
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.Write("{0} Exception caught.", e.ToString());
                        MessageBox.Show("Error parsing Prefetch file"); //e.ToString(),Path.GetFileName(i));
                        Trace.Flush();
                    }
                    finally
                    {
                        R.Close();
                    }
                }
                else if (Path.GetExtension(i) != ".pf")
                {
                }
            }
            if (pffilefalse_counter > 0)
            {
                MessageBox.Show(String.Concat(pffilefalse_counter, " invalid PF files found"), "Error");
            }
            return pffiletrue_counter;
        }

        private void parsepffilefolder_dowork(string[] selected_items)
        {
            // define our variables
            byte[] temp4 = new byte[4];
            byte[] temp1 = new byte[1];
            byte[] temp2 = new byte[2];
            byte[] temp8 = new byte[8];

            DataTable pfinfosubfile = new DataTable("pfinfosub");
            pfinfosubfile.Columns.Add("File Name", typeof(string));
            pfinfosubfile.Columns.Add("Path", typeof(string));
            DataTable pfinfosubfolder = new DataTable("pfinfosub");
            pfinfosubfolder.Columns.Add("File Name", typeof(string));
            pfinfosubfolder.Columns.Add("Path", typeof(string));

            foreach (string i in selected_items)
            {
                // lets go through all the files one by one
                if (Path.GetExtension(i) == ".pf")
                {
                    using (BinaryReader R = new BinaryReader(File.Open(i, FileMode.Open, FileAccess.Read, FileShare.Read)))
                        try
                        {
                            //get file ref offset
                            R.BaseStream.Position = 100;
                            R.Read(temp4, 0, 4);
                            int file_ref_offset = BitConverter.ToInt32(temp4, 0);

                            //get file ref length
                            R.BaseStream.Position = 104;
                            R.Read(temp4, 0, 4);
                            int file_ref_length = BitConverter.ToInt32(temp4, 0);

                            //get volume information offset
                            R.BaseStream.Position = 108;
                            R.Read(temp4, 0, 4);
                            int vol_info_offset = BitConverter.ToInt32(temp4, 0);

                            //get the folder reference area offset
                            R.BaseStream.Position = vol_info_offset + 28;
                            R.Read(temp4, 0, 4);
                            int folder_ref_offset = BitConverter.ToInt32(temp4, 0);
                            folder_ref_offset = vol_info_offset + folder_ref_offset + 2; // we need the +2 as it is unicode
                            R.BaseStream.Position = vol_info_offset + 28 + 4;
                            R.Read(temp4, 0, 4);
                            int folder_ref_number = BitConverter.ToInt32(temp4, 0);

                            //lets go through all the file references
                            int byte11 = 1;
                            string temp11 = "";
                            string[] filerefs = new string[5000];
                            R.BaseStream.Position = file_ref_offset;
                            int tempor = file_ref_offset;
                            int endoffileref = file_ref_offset + file_ref_length;
                            int temppos = 0;
                            while (tempor < endoffileref)
                            {
                                byte11 = 1;
                                temp11 = "";
                                // we need to check the first byte as this is sometimes null
                                R.Read(temp4, 0, 1);
                                // if the first byte isn't null then lets read the rest of the string
                                while (byte11 != 0) // save name as a string, stop when you get to null
                                {
                                    R.BaseStream.Position = tempor;
                                    R.Read(temp1, 0, 1);
                                    R.Read(temp4, 0, 2); // we have to read this into a 4 byte array (there is no ToInt8)
                                    byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                    temp11 = System.Text.Encoding.Default.GetString(temp1);
                                    filerefs[temppos] = filerefs[temppos] + temp11;
                                    tempor = tempor + 2; // we are reading a unicode value here
                                }
                                // write data into database
                                pfinfosubfile.Rows.Add(Path.GetFileName(i), filerefs[temppos]);
                                temppos++;
                                tempor = tempor + 2; // move past the null
                            }

                            //lets go through all the folder references
                            string[] folderrefs = new string[folder_ref_number];
                            R.BaseStream.Position = folder_ref_offset;
                            tempor = folder_ref_offset;
                            temppos = 0;
                            int x = 0;
                            while (x < folder_ref_number)
                            {
                                byte11 = 1;
                                temp11 = "";
                                while (byte11 != 0) // save name as a string, stop when you get to null
                                {
                                    R.BaseStream.Position = tempor;
                                    R.Read(temp1, 0, 1);
                                    R.Read(temp4, 0, 2); // we have to read this into a 4 byte array (there is no ToInt8)
                                    byte11 = BitConverter.ToInt16(temp4, 0); // check for null
                                    temp11 = System.Text.Encoding.Default.GetString(temp1);
                                    folderrefs[temppos] = folderrefs[temppos] + temp11;
                                    tempor = tempor + 2; // we are reading a unicode value here
                                }
                                // write data into database
                                pfinfosubfolder.Rows.Add(Path.GetFileName(i), folderrefs[temppos]);
                                temppos++;
                                tempor = tempor + 4; // +4 to go past the 2 nulls in unicode
                                x++;
                            }
                        }
                        catch (Exception e)
                        {
                            Trace.Write("{0} Exception caught.", e.ToString());
                            MessageBox.Show("Error parsing prefetch file/folder structures"); //e.ToString(),Path.GetFileName(i));
                            Trace.Flush();
                        }
                        finally
                        {
                            dataGridpfinfosub_fileref.DataSource = pfinfosubfile;
                            dataGridpfinfosub_folderref.DataSource = pfinfosubfolder;
                        }
                }
            }
        }

        private void parsepf_finalisetable(DataTable datatable, DataGridView gridview, Panel panel)
        {
            // Set the gridview datasource.
            gridview.DataSource = datatable;

            // set formatting of columns
            gridview.Columns["Last Run Time (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["Volume Created Date (Local)"].DefaultCellStyle.Format = "dd/MM/yyyy HH:mm:ss";
            gridview.Columns["FullPath"].Visible = false;

            //correct column sizes
            for (int i = 0; i < gridview.Columns.Count; i++)
            {
                int colw = gridview.Columns[i].Width;
                gridview.Columns[i].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
                gridview.Columns[i].Width = colw;
            }
            gridview.Refresh();
            dataGridview_pfinfo.Visible = true;
            toUTCToolStripMenuItem_pf.Visible = true;
        }

        private DateTime? ReadTargetLnkTime(int i, BinaryReader j, byte[] k, string timezone, string fixup, int fixup_value)
        {
            // declare vars
            long filetime;
            // do work
            j.BaseStream.Position = i;
            if (fixup == "no")
            {
                j.Read(k, 0, 8);
            }
            else if (fixup == "yes")
            {
                j.Read(k, 0, 6);
                byte[] intBytes = BitConverter.GetBytes(fixup_value);
                byte[] newArray = new byte[k.Length];
                k.CopyTo(newArray, 0);
                newArray[6] = intBytes[0];
                newArray[7] = intBytes[1];
                k = newArray;
                string temppor = bytestostring(k, null);
                filetime = BitConverter.ToInt64(k, 0);
            }
            filetime = BitConverter.ToInt64(k, 0);
            if (filetime > 0)
            {
                if (timezone == "utc") { return DateTime.FromFileTimeUtc(filetime); }
                else if (timezone == "local") { return DateTime.FromFileTime(filetime); }
                else { return null; }
            }
            else { return null; }
        }

        private DateTime ReadTargetLnkTime_noq(int i, BinaryReader j, byte[] k, string timezone)
        {
            // declare vars
            long filetime;
            // do work
            j.BaseStream.Position = i;
            j.Read(k, 0, 8);
            filetime = BitConverter.ToInt64(k, 0);
            if (timezone == "utc") { return DateTime.FromFileTimeUtc(filetime); }
            else { return DateTime.FromFileTime(filetime); } //(timezone == "local")
        }

        public string parseStringData(BinaryReader R, int CurrentPosition, out int NewPosition)
        {
            byte[] temp2 = new byte[2];
            int StringData_temp;
            string varname;
            R.BaseStream.Position = CurrentPosition;
            R.Read(temp2, 0, 2);
            StringData_temp = BitConverter.ToInt16(temp2, 0);
            StringData_temp = StringData_temp * 2; // we are reading Unicode values here
            byte[] StringData_String = new byte[StringData_temp];
            R.BaseStream.Position = CurrentPosition + 2; // lets move to that string
            R.Read(StringData_String, 0, StringData_temp);
            varname = System.Text.Encoding.Unicode.GetString(StringData_String);
            NewPosition = CurrentPosition + 2 + StringData_temp;
            return varname;
        }

        private void folderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folder_browser = new FolderBrowserDialog();
            if (folder_browser.ShowDialog() == DialogResult.OK)
            {
                // First we must setup the tables.
                DataTable lnkinfo = new DataTable("lnkinfo");
                parselnk_setuptable(lnkinfo, panel_lnk, "lnk only");

                worker_lnk_vars lnk_vars = new worker_lnk_vars
                {
                    path = folder_browser.SelectedPath,
                    datatable = lnkinfo,
                    datagridview = dataGridView_lnk,
                    panel = panel_lnk
                };
                worker_lnk.RunWorkerAsync(lnk_vars);
            }
        }

        private void worker_lnk_DoWork(object sender, DoWorkEventArgs e)
        {
            // Now we must do the work.
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int filecount;

            worker_lnk_vars vars = e.Argument as worker_lnk_vars;
            if (vars.flags == 1) // we have a drag and drop operation!
            {
                filecount = parselnk_dowork(vars.list_of_files.ToArray(), vars.datatable);
            }
            else //continue with normal operations
            {
                filecount = parselnk_dowork(Directory.GetFiles(vars.path), vars.datatable);
            }
            vars.filecount = filecount;

            sw.Stop();
            statuslabel_lnk_timetaken.Text = String.Concat("Take taken: ", sw.Elapsed.TotalSeconds.ToString(), " seconds.");
            statuslabel_lnk_filesparsed.Text = String.Concat(filecount.ToString(), " .lnk files parsed.");

            e.Result = vars; 
        }

        class worker_lnk_vars
        {
            public List<string> list_of_files { get; set; }
            public string path { get; set; }
            public DataTable datatable { get; set; }
            public DataGridView datagridview { get; set; }
            public Panel panel { get; set; }
            public int flags { get; set; }
            public int filecount { get; set; }
        }

        private void worker_lnk_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            worker_lnk_vars vars = e.Result as worker_lnk_vars;
            parselnk_finalisetable(vars.datatable, vars.datagridview, vars.panel);
            statuslabel_lnk_filebeingparsed.Text = "";
            toUTCToolStripMenuItem_lnk.Visible = true;
            toLocalToolStripMenuItem_lnk.Visible = false;
            dataGridView_lnk.Columns["Embedded Creation Time (Local)"].HeaderText = String.Concat("Embedded Creation Time (Local)");
            dataGridView_lnk.Columns["Embedded Access Time (Local)"].HeaderText = String.Concat("Embedded Access Time (Local)");
            dataGridView_lnk.Columns["Embedded Written Time (Local)"].HeaderText = String.Concat("Embedded Written Time (Local)");
            toLocalToolStripMenuItem_lnk.Visible = false;
            toUTCToolStripMenuItem_lnk.Visible = true;
            tabPage_lnk.Text = string.Concat(".lnk Results - ", vars.filecount);
        }

        private void toUTCToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_lnk.Visible = false;
            toLocalToolStripMenuItem_lnk.Visible = true;
            changetimezone_lnk(dataGridView_lnk, "UTC");
        }

        private void changetimezone_lnk(DataGridView gridview, string timezone)
        {
            foreach (DataGridViewRow row in gridview.Rows)
            {
                DataGridViewCell cell1 = row.Cells["Embedded Creation Time (Local)"];
                {
                    if (cell1.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell1.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        else if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell1.Value = x;
                    }
                }
                gridview.Columns["Embedded Creation Time (Local)"].HeaderText = String.Concat("Embedded Creation Time (", timezone, ")");
                DataGridViewCell cell2 = row.Cells["Embedded Written Time (Local)"];
                {
                    if (cell2.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell2.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell2.Value = x;
                    }
                }
                gridview.Columns["Embedded Written Time (Local)"].HeaderText = String.Concat("Embedded Written Time (", timezone, ")");
                DataGridViewCell cell3 = row.Cells["Embedded Access Time (Local)"];
                {
                    if (cell3.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell3.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell3.Value = x;
                    }
                }
                gridview.Columns["Embedded Access Time (Local)"].HeaderText = String.Concat("Embedded Access Time (", timezone, ")");

                DataGridViewCell cell4 = row.Cells["LNK File Creation Time (Local)"];
                {
                    if (cell3.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell4.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell4.Value = x;
                    }
                }
                gridview.Columns["LNK File Creation Time (Local)"].HeaderText = String.Concat("LNK File Creation Time (", timezone, ")");

                DataGridViewCell cell5 = row.Cells["LNK File Written Time (Local)"];
                {
                    if (cell3.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell5.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell3.Value = x;
                    }
                }
                gridview.Columns["LNK File Written Time (Local)"].HeaderText = String.Concat("LNK File Written Time (", timezone, ")");

                DataGridViewCell cell6 = row.Cells["LNK File Access Time (Local)"];
                {
                    if (cell3.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell6.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell3.Value = x;
                    }
                }
                gridview.Columns["LNK File Access Time (Local)"].HeaderText = String.Concat("LNK File Access Time (", timezone, ")");
            }
            gridview.Refresh();
        }

        private void changetimezone_pf(string timezone)
        {
            foreach (DataGridViewRow row in dataGridview_pfinfo.Rows)
            {
                DataGridViewCell cell1 = row.Cells["Last Run Time (Local)"];
                {
                    if (cell1.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell1.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell1.Value = x;
                    }
                }
                dataGridview_pfinfo.Columns["Last Run Time (Local)"].HeaderText = String.Concat("Last Run Time (", timezone, ")");
                DataGridViewCell cell2 = row.Cells["Volume Created Date (Local)"];
                {
                    if (cell2.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell2.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell2.Value = x;
                    }
                }
                dataGridview_pfinfo.Columns["Volume Created Date (Local)"].HeaderText = String.Concat("Volume Created Date (", timezone, ")");
            }
            dataGridview_pfinfo.Refresh();
        }

        private void changetimezone_i30(string timezone)
        {
            foreach (DataGridViewRow row in dataGridView_i30.Rows)
            {
                DataGridViewCell cell1 = row.Cells["Creation Time (Local)"];
                {
                    if (cell1.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell1.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell1.Value = x;
                    }
                }
                dataGridView_i30.Columns["Creation Time (Local)"].HeaderText = String.Concat("Creation Time (", timezone, ")");
                
                DataGridViewCell cell2 = row.Cells["Last Modified Time (Local)"];
                {
                    if (cell2.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell2.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell2.Value = x;
                    }
                }
                dataGridView_i30.Columns["Last Modified Time (Local)"].HeaderText = String.Concat("Last Modified Time (", timezone, ")");

                DataGridViewCell cell3 = row.Cells["Last Access Time (Local)"];
                {
                    if (cell3.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell3.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell3.Value = x;
                    }
                }
                dataGridView_i30.Columns["Last Access Time (Local)"].HeaderText = String.Concat("Last Access Time (", timezone, ")");

                DataGridViewCell cell4 = row.Cells["MFT Record Change Time (Local)"];
                {
                    if (cell4.Value != DBNull.Value)
                    {
                        DateTime x = (DateTime)cell4.Value;
                        if (timezone == "UTC")
                        {
                            x = x.ToUniversalTime();
                        }
                        if (timezone == "Local")
                        {
                            x = x.ToLocalTime();
                        }
                        cell4.Value = x;
                    }
                }
                dataGridView_i30.Columns["MFT Record Change Time (Local)"].HeaderText = String.Concat("MFT Record Change Time (", timezone, ")");
            }
            dataGridView_i30.Refresh();
        }

        private void toLocalToolStripMenuItem_lnk_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_lnk.Visible = true;
            toLocalToolStripMenuItem_lnk.Visible = false;
            changetimezone_lnk(dataGridView_lnk, "Local");
        }

        private void recentFolderLocalMachineToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // First we must setup the tables.
            DataTable lnkinfo = new DataTable("lnkinfo");
            parselnk_setuptable(lnkinfo, panel_lnk, "lnk only");

            worker_lnk_vars lnk_vars = new worker_lnk_vars
            {
                path = String.Concat(System.Environment.GetEnvironmentVariable("USERPROFILE"), @"\AppData\Roaming\Microsoft\Windows\Recent"),
                datatable = lnkinfo,
                datagridview = dataGridView_lnk,
                panel = panel_lnk
            };
            worker_lnk.RunWorkerAsync(lnk_vars);
        }

        private void toCSVToolStripMenuItem_Click(object sender, EventArgs e)
        {
            savecsv_format(dataGridView_lnk);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //File.Delete("sfp-log.txt");
            Close();
        }

        private void folderToolStripMenuItem_pfparsefolder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folder_browser = new FolderBrowserDialog();
            if (folder_browser.ShowDialog() == DialogResult.OK)
            {
                // First we must setup the tables.
                DataTable pfinfo = new DataTable("pfinfo");
                parsepf_setuptable(pfinfo, panel_pf);

                worker_lnk_vars pf_vars = new worker_lnk_vars
                {
                    path = folder_browser.SelectedPath,
                    datatable = pfinfo,
                    datagridview = dataGridview_pfinfo,
                    panel = panel_pf
                };
                worker_pf.RunWorkerAsync(pf_vars);
            }
        }

        private void prefetchFolderLocalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            object temp = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters", "EnablePrefetcher", 0);
            string temp1 = temp.ToString(); // save this setting
            Trace.Write(String.Concat(";" + ";" + "Prefetch setting is " + temp1 + "\n"));
            Trace.Write(String.Concat(";" + ";" + "Parsing of the Local Machine's PF dir selected\n"));
            string SelectedPath;
            SelectedPath = String.Concat(System.Environment.GetEnvironmentVariable("SystemRoot"), @"\Prefetch");
            Trace.Write(String.Concat(";" + ";" + "Local Directory is " + SelectedPath + "\n"));

            // First we must setup the tables.
            DataTable pfinfo = new DataTable("pfinfo");
            parsepf_setuptable(pfinfo, panel_pf);

            worker_lnk_vars pf_vars = new worker_lnk_vars
            {
                path = SelectedPath,
                datatable = pfinfo,
                datagridview = dataGridview_pfinfo,
                panel = panel_pf
            };
            worker_pf.RunWorkerAsync(pf_vars);
        }

        private void worker_pf_DoWork(object sender, DoWorkEventArgs e)
        {
            // Now we must do the work.
            Stopwatch sw = new Stopwatch();
            sw.Start();
            int filecount;
            worker_lnk_vars vars = e.Argument as worker_lnk_vars;

            if (vars.flags == 1) // we have a drag and drop operation!
            {
                filecount = parsepf_dowork(vars.list_of_files.ToArray(), vars.datatable);
            }
            else //continue with normal operations
            {
                filecount = parsepf_dowork(Directory.GetFiles(vars.path), vars.datatable);
            }
            vars.filecount = filecount;
            
            sw.Stop();
            statuslabel_pf_timetaken.Text = String.Concat("Take taken: ", sw.Elapsed.TotalSeconds.ToString(), " seconds.");
            statuslabel_pf_filesparsed.Text = String.Concat(filecount.ToString(), " PF files parsed.");
            e.Result = vars;
        }

        private void worker_pf_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            worker_lnk_vars vars = e.Result as worker_lnk_vars;
            parsepf_finalisetable(vars.datatable, vars.datagridview, vars.panel);
            statuslabel_pf_filebeingparsed.Text = "";
            dataGridview_pfinfo.Columns["Volume Created Date (Local)"].HeaderText = String.Concat("Volume Created Date (Local)");
            dataGridview_pfinfo.Columns["Last Run Time (Local)"].HeaderText = String.Concat("Last Run Time (Local)");
            toLocalToolStripMenuItem_pf.Visible = false;
            toUTCToolStripMenuItem_pf.Visible = true;
            tabPage_pf.Text = string.Concat("Prefetch Results - ", vars.filecount);
        }

        private void toUTCToolStripMenuItem_pf_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_pf.Visible = false;
            toLocalToolStripMenuItem_pf.Visible = true;
            changetimezone_pf("UTC");
        }

        private void toLocalToolStripMenuItem_pf_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_pf.Visible = true;
            toLocalToolStripMenuItem_pf.Visible = false;
            changetimezone_pf("Local");
        }

        private void toCSVToolStripMenuItem_Click_1(object sender, EventArgs e)
        {
            savecsv_format(dataGridview_pfinfo);
        }

        private void selectedRowsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int selectedRowCount = dataGridview_pfinfo.Rows.GetRowCount(DataGridViewElementStates.Selected);
            string[] selectedrows = new string[dataGridview_pfinfo.Rows.GetRowCount(DataGridViewElementStates.Selected)];
            if (selectedRowCount > 0)
            {
                for (int i = 0; i < selectedRowCount; i++)
                {
                    selectedrows[i] = dataGridview_pfinfo["FullPath", dataGridview_pfinfo.SelectedRows[i].Index].Value.ToString();
                }
            }
            parsepffilefolder_dowork(selectedrows);
            splitContainer_pf.Panel2Collapsed = false;
        }

        private void toCSVToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            SaveFileDialog s = new SaveFileDialog();
            s.Filter = "CSV Files (*.csv)|*.csv";
            if (s.ShowDialog() == DialogResult.OK)
            {
                string buffer_csv_return = "\r\n";
                // Create the output CSV file
                TextWriter T = new StreamWriter(s.FileName);
                DataTable csvoutput = dataGridpfinfosub_fileref.DataSource as DataTable;
                // print file info first

                // print column names first
                foreach (DataColumn column in csvoutput.Columns)
                {
                    string buffer_csv = string.Concat(column.ColumnName, ","); T.Write(buffer_csv);
                }
                T.Write(buffer_csv_return);

                // now print the file references
                foreach (DataRow row in csvoutput.Rows)
                {
                    foreach (DataColumn column in csvoutput.Columns)
                    {
                        string buffer_csv = string.Concat(row[column], ","); T.Write(buffer_csv);
                    }
                    T.Write(buffer_csv_return);
                }

                csvoutput = dataGridpfinfosub_folderref.DataSource as DataTable;
                // now print the folder references
                foreach (DataRow row in csvoutput.Rows)
                {
                    foreach (DataColumn column in csvoutput.Columns)
                    {
                        string buffer_csv = string.Concat(row[column], ","); T.Write(buffer_csv);
                    }
                    T.Write(buffer_csv_return);
                }

                // close the file
                T.Close();
                MessageBox.Show(string.Concat(Path.GetFileName(s.FileName), " saved sucessfully"));
            }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Simple File Parser v1.5.1 created by Chris Mayhew\n\nsimplefileparser.blogspot.com\nctmayhew@gmail.com", "About");
        }

        private void oNToolStripMenuItem_Click(object sender, EventArgs e)
        {
            logging = "on";
            oNToolStripMenuItem.Visible = false;
            oFFToolStripMenuItem.Visible = true;
        }

        private void oFFToolStripMenuItem_Click(object sender, EventArgs e)
        {
            logging = "off";
            oNToolStripMenuItem.Visible = true;
            oFFToolStripMenuItem.Visible = false;
        }

        private void centralStandardTimeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_lnk.Visible = true;
            toLocalToolStripMenuItem_lnk.Visible = true;
            centralStandardTimeToolStripMenuItem_LNK.Visible = false;
            changetimezone_lnk(dataGridView_lnk, "Central Standard Time");
        }

        private void automaticDestinationsFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // create the data table for the jump list info
            DataTable jlinfo = new DataTable("pfinfo");

            FolderBrowserDialog d = new FolderBrowserDialog();
            if (d.ShowDialog() == DialogResult.OK)
            {
                parsejl_setuptable(jlinfo, panel_jl); //setup the jl table and columns

                string[] filePaths = Directory.GetFiles(d.SelectedPath);
                // lets quickly check all the file headers so the progress bar reports well
                foreach (string i in filePaths)
                {
                    if (Path.GetExtension(i) == ".automaticDestinations-ms")
                    {
                        //get the app id name first
                        string appid_name = getapid(Path.GetFileNameWithoutExtension(i));
                        //now get MD5 hash
                        FileStream fileStream = new FileStream(i, FileMode.Open, FileAccess.Read, FileShare.Read);
                        string md5hash = GetMD5HashFromStream(fileStream);
                        jlinfo.Rows.Add(Path.GetFileName(i), appid_name, md5hash, i);
                    }
                }
                parsejl_finalisetable(jlinfo, dataGridjlinfo, panel_jl); //finalise the table
            }
        }

        private void parseSelectedJumpListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            int selectedRowCount = dataGridjlinfo.Rows.GetRowCount(DataGridViewElementStates.Selected);
            string[] selectedrows = new string[dataGridjlinfo.Rows.GetRowCount(DataGridViewElementStates.Selected)];
            if (selectedRowCount > 0)
            {
                for (int i = 0; i < selectedRowCount; i++)
                {
                    selectedrows[i] = dataGridjlinfo["FullPath", dataGridjlinfo.SelectedRows[i].Index].Value.ToString();
                }
            }
            parsejumplist_dowork(selectedrows);
            splitContainerjl.Panel2Collapsed = false;
            embeddedInfoToolStripMenuItem.Enabled = true;
            desListInfoToolStripMenuItem.Enabled = true;
            toUTCToolStripMenuItem_jl.Visible = true;
            toLocalToolStripMenuItem_jl.Visible = false;
            dataGridViewjl_lnk.Columns["Creation Time (Local)"].HeaderText = String.Concat("Creation Time (Local)");
            dataGridViewjl_lnk.Columns["Access Time (Local)"].HeaderText = String.Concat("Creation Time (Local)");
            dataGridViewjl_lnk.Columns["Written Time (Local)"].HeaderText = String.Concat("Creation Time (Local)");
        }

        private void toUTCToolStripMenuItem_jl_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_jl.Visible = false;
            toLocalToolStripMenuItem_jl.Visible = true;
            changetimezone_lnk(dataGridViewjl_lnk, "UTC");
        }

        private void toLocalToolStripMenuItem_jl_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_jl.Visible = true;
            toLocalToolStripMenuItem_jl.Visible = false;
            changetimezone_lnk(dataGridViewjl_lnk, "Local");
        }

        private void toCSVToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            savecsv_format(dataGridjlinfo);
        }

        private void toCSVToolStripMenuItem3_Click(object sender, EventArgs e)
        {
            savecsv_format(dataGridViewjl_lnk);
        }

        private void toCSVToolStripMenuItem4_Click(object sender, EventArgs e)
        {
            savecsv_format(dataGridViewjl_destlist);
        }

        private void folderOfI30FilesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog folder_browser = new FolderBrowserDialog();
            if (folder_browser.ShowDialog() == DialogResult.OK)
            {
                // First we must setup the tables.
                DataTable i30info = new DataTable("i30info");
                parsei30_setuptable(i30info, paneli30);

                worker_lnk_vars i30_vars = new worker_lnk_vars
                {
                    path = folder_browser.SelectedPath,
                    datatable = i30info,
                    datagridview = dataGridView_i30,
                    panel = paneli30
                };
                worker_i30.RunWorkerAsync(i30_vars);
            }
        }

        private void worker_i30_DoWork(object sender, DoWorkEventArgs e)
        {
            // Now we must do the work.
            Stopwatch sw = new Stopwatch();
            int filecount;
            sw.Start();

            worker_lnk_vars vars = e.Argument as worker_lnk_vars;

            if (vars.flags == 1) // we have a drag and drop operation!
            {
                filecount = parsei30_dowork(vars.list_of_files.ToArray(), vars.datatable);
            }
            else //continue with normal operations
            {
                filecount = parsei30_dowork(Directory.GetFiles(vars.path), vars.datatable);
            }
            vars.filecount = filecount;

            sw.Stop();
            statuslabel_i30_timetaken.Text = String.Concat("Take taken: ", sw.Elapsed.TotalSeconds.ToString(), " seconds.");
            statuslabel_i30_filesparsed.Text = String.Concat(filecount.ToString(), " $I30 files parsed.");

            e.Result = vars; 
        }

        private void worker_i30_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            worker_lnk_vars vars = e.Result as worker_lnk_vars;
            parsei30_finalisetable(vars.datatable, vars.datagridview, vars.panel);
            statuslabel_i30_filebeingparsed.Text = "";
            toUTCToolStripMenuItem_i30.Visible = true;
            paneli30.Visible = true;
            tabpage_i30.Text = string.Concat("$I30 Results - ", vars.filecount);
        }

        private void toCSVToolStripMenuItem_i30_Click(object sender, EventArgs e)
        {
            savecsv_format(dataGridView_i30);
        }

        private void toLocalToolStripMenuItem_i30_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_i30.Visible = true;
            toLocalToolStripMenuItem_i30.Visible = false;
            changetimezone_i30("Local");
        }

        private void toUTCToolStripMenuItem_i30_Click(object sender, EventArgs e)
        {
            toUTCToolStripMenuItem_i30.Visible = false;
            toLocalToolStripMenuItem_i30.Visible = true;
            changetimezone_i30("UTC");
        }

        private void SFP_main_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        private void SFP_main_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
                List<string> all_files = new List<string>();

                //create the lists we need for parsing each file
                List<string> lnk_files = new List<string>();
                List<string> pf_files = new List<string>();
                List<string> jl_files = new List<string>();
                List<string> i30_files = new List<string>();

                foreach (string fileName in files)
                {
                    //check to see if it a directory - we need to enumarate these - ONE level only.
                    if (Directory.Exists(fileName))
                    {
                        
                        //Add files from folder
                        foreach (string s in Directory.GetFiles(fileName))
                        {
                            all_files.Add(s);
                            switch (Path.GetExtension(s))
                            {
                                case ".lnk":
                                    lnk_files.Add(s); break;
                                case ".pf":
                                    pf_files.Add(s); break;
                                default: break;
                            }
                        }
                    }
                    else
                    {
                        string s = fileName;
                        all_files.Add(s);
                        switch (Path.GetExtension(s))
                        {
                            case ".lnk":
                                lnk_files.Add(s); break;
                            case ".pf":
                                pf_files.Add(s); break;
                            default: break;
                        }

                    }
                }

                //now lets go do the work!
                if (lnk_files.Any()) //we need to check if the array contains any data
                {
                    // First we must setup the tables.
                    DataTable lnkinfo = new DataTable("lnkinfo");
                    parselnk_setuptable(lnkinfo, panel_lnk, "lnk only");

                    worker_lnk_vars lnk_vars = new worker_lnk_vars
                    {
                        list_of_files = lnk_files,
                        datatable = lnkinfo,
                        datagridview = dataGridView_lnk,
                        panel = panel_lnk,
                        flags = 1
                    };
                    worker_lnk.RunWorkerAsync(lnk_vars);
                }

                if (pf_files.Any())
                {
                    // First we must setup the tables.
                    DataTable pfinfo = new DataTable("pfinfo");
                    parsepf_setuptable(pfinfo, panel_pf);

                    worker_lnk_vars pf_vars = new worker_lnk_vars
                    {
                        list_of_files = pf_files,
                        datatable = pfinfo,
                        datagridview = dataGridview_pfinfo,
                        flags = 1
                    };
                    worker_pf.RunWorkerAsync(pf_vars);
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Error in DragDrop function: " + ex.Message);

                // don't show MessageBox here - Explorer is waiting !
            }
        }
    }
}
